{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"http://hilpisch.com/tpq_logo.png\" alt=\"The Python Quants\" width=\"35%\" align=\"right\" border=\"0\"><br>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Python for Finance (2nd ed.)\n",
    "\n",
    "**Mastering Data-Driven Finance**\n",
    "\n",
    "&copy; Dr. Yves J. Hilpisch | The Python Quants GmbH\n",
    "\n",
    "<img src=\"http://hilpisch.com/images/py4fi_2nd_shadow.png\" width=\"300px\" align=\"left\">"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Performance Python"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Loops"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Python"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import random"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "def average_py(n):\n",
    "    s = 0  \n",
    "    for i in range(n):\n",
    "        s += random.random()  \n",
    "    return s / n  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "n = 10000000  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 1.16 s, sys: 6.02 ms, total: 1.17 s\n",
      "Wall time: 1.17 s\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "0.5000288134401795"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time average_py(n)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1.21 s ± 29.9 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
     ]
    }
   ],
   "source": [
    "%timeit average_py(n)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 1.29 s, sys: 146 ms, total: 1.44 s\n",
      "Wall time: 1.45 s\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "0.4999999755573351"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time sum([random.random() for _ in range(n)]) / n  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### NumPy "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "def average_np(n):\n",
    "    s = np.random.random(n)  \n",
    "    return s.mean()  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 98.6 ms, sys: 21.9 ms, total: 120 ms\n",
      "Wall time: 119 ms\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "0.4999295623334985"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time average_np(n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "89.3 ms ± 2.88 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n"
     ]
    }
   ],
   "source": [
    "%timeit average_np(n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "80000000"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s = np.random.random(n)\n",
    "s.nbytes  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Numba"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numba"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "average_nb = numba.jit(average_py)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 186 ms, sys: 26.4 ms, total: 212 ms\n",
      "Wall time: 211 ms\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "0.5000401086881164"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time average_nb(n)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 47.4 ms, sys: 149 µs, total: 47.5 ms\n",
      "Wall time: 47.4 ms\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "0.4998864487902267"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time average_nb(n)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "47.8 ms ± 1.23 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n"
     ]
    }
   ],
   "source": [
    "%timeit average_nb(n)  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Cython"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "%load_ext Cython"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<!DOCTYPE html>\n",
       "<!-- Generated by Cython 0.29.20 -->\n",
       "<html>\n",
       "<head>\n",
       "    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n",
       "    <title>Cython: _cython_magic_df7795ef4529753db07280ca67f4c5d6.pyx</title>\n",
       "    <style type=\"text/css\">\n",
       "    \n",
       "body.cython { font-family: courier; font-size: 12; }\n",
       "\n",
       ".cython.tag  {  }\n",
       ".cython.line { margin: 0em }\n",
       ".cython.code { font-size: 9; color: #444444; display: none; margin: 0px 0px 0px 8px; border-left: 8px none; }\n",
       "\n",
       ".cython.line .run { background-color: #B0FFB0; }\n",
       ".cython.line .mis { background-color: #FFB0B0; }\n",
       ".cython.code.run  { border-left: 8px solid #B0FFB0; }\n",
       ".cython.code.mis  { border-left: 8px solid #FFB0B0; }\n",
       "\n",
       ".cython.code .py_c_api  { color: red; }\n",
       ".cython.code .py_macro_api  { color: #FF7000; }\n",
       ".cython.code .pyx_c_api  { color: #FF3000; }\n",
       ".cython.code .pyx_macro_api  { color: #FF7000; }\n",
       ".cython.code .refnanny  { color: #FFA000; }\n",
       ".cython.code .trace  { color: #FFA000; }\n",
       ".cython.code .error_goto  { color: #FFA000; }\n",
       "\n",
       ".cython.code .coerce  { color: #008000; border: 1px dotted #008000 }\n",
       ".cython.code .py_attr { color: #FF0000; font-weight: bold; }\n",
       ".cython.code .c_attr  { color: #0000FF; }\n",
       ".cython.code .py_call { color: #FF0000; font-weight: bold; }\n",
       ".cython.code .c_call  { color: #0000FF; }\n",
       "\n",
       ".cython.score-0 {background-color: #FFFFff;}\n",
       ".cython.score-1 {background-color: #FFFFe7;}\n",
       ".cython.score-2 {background-color: #FFFFd4;}\n",
       ".cython.score-3 {background-color: #FFFFc4;}\n",
       ".cython.score-4 {background-color: #FFFFb6;}\n",
       ".cython.score-5 {background-color: #FFFFaa;}\n",
       ".cython.score-6 {background-color: #FFFF9f;}\n",
       ".cython.score-7 {background-color: #FFFF96;}\n",
       ".cython.score-8 {background-color: #FFFF8d;}\n",
       ".cython.score-9 {background-color: #FFFF86;}\n",
       ".cython.score-10 {background-color: #FFFF7f;}\n",
       ".cython.score-11 {background-color: #FFFF79;}\n",
       ".cython.score-12 {background-color: #FFFF73;}\n",
       ".cython.score-13 {background-color: #FFFF6e;}\n",
       ".cython.score-14 {background-color: #FFFF6a;}\n",
       ".cython.score-15 {background-color: #FFFF66;}\n",
       ".cython.score-16 {background-color: #FFFF62;}\n",
       ".cython.score-17 {background-color: #FFFF5e;}\n",
       ".cython.score-18 {background-color: #FFFF5b;}\n",
       ".cython.score-19 {background-color: #FFFF57;}\n",
       ".cython.score-20 {background-color: #FFFF55;}\n",
       ".cython.score-21 {background-color: #FFFF52;}\n",
       ".cython.score-22 {background-color: #FFFF4f;}\n",
       ".cython.score-23 {background-color: #FFFF4d;}\n",
       ".cython.score-24 {background-color: #FFFF4b;}\n",
       ".cython.score-25 {background-color: #FFFF48;}\n",
       ".cython.score-26 {background-color: #FFFF46;}\n",
       ".cython.score-27 {background-color: #FFFF44;}\n",
       ".cython.score-28 {background-color: #FFFF43;}\n",
       ".cython.score-29 {background-color: #FFFF41;}\n",
       ".cython.score-30 {background-color: #FFFF3f;}\n",
       ".cython.score-31 {background-color: #FFFF3e;}\n",
       ".cython.score-32 {background-color: #FFFF3c;}\n",
       ".cython.score-33 {background-color: #FFFF3b;}\n",
       ".cython.score-34 {background-color: #FFFF39;}\n",
       ".cython.score-35 {background-color: #FFFF38;}\n",
       ".cython.score-36 {background-color: #FFFF37;}\n",
       ".cython.score-37 {background-color: #FFFF36;}\n",
       ".cython.score-38 {background-color: #FFFF35;}\n",
       ".cython.score-39 {background-color: #FFFF34;}\n",
       ".cython.score-40 {background-color: #FFFF33;}\n",
       ".cython.score-41 {background-color: #FFFF32;}\n",
       ".cython.score-42 {background-color: #FFFF31;}\n",
       ".cython.score-43 {background-color: #FFFF30;}\n",
       ".cython.score-44 {background-color: #FFFF2f;}\n",
       ".cython.score-45 {background-color: #FFFF2e;}\n",
       ".cython.score-46 {background-color: #FFFF2d;}\n",
       ".cython.score-47 {background-color: #FFFF2c;}\n",
       ".cython.score-48 {background-color: #FFFF2b;}\n",
       ".cython.score-49 {background-color: #FFFF2b;}\n",
       ".cython.score-50 {background-color: #FFFF2a;}\n",
       ".cython.score-51 {background-color: #FFFF29;}\n",
       ".cython.score-52 {background-color: #FFFF29;}\n",
       ".cython.score-53 {background-color: #FFFF28;}\n",
       ".cython.score-54 {background-color: #FFFF27;}\n",
       ".cython.score-55 {background-color: #FFFF27;}\n",
       ".cython.score-56 {background-color: #FFFF26;}\n",
       ".cython.score-57 {background-color: #FFFF26;}\n",
       ".cython.score-58 {background-color: #FFFF25;}\n",
       ".cython.score-59 {background-color: #FFFF24;}\n",
       ".cython.score-60 {background-color: #FFFF24;}\n",
       ".cython.score-61 {background-color: #FFFF23;}\n",
       ".cython.score-62 {background-color: #FFFF23;}\n",
       ".cython.score-63 {background-color: #FFFF22;}\n",
       ".cython.score-64 {background-color: #FFFF22;}\n",
       ".cython.score-65 {background-color: #FFFF22;}\n",
       ".cython.score-66 {background-color: #FFFF21;}\n",
       ".cython.score-67 {background-color: #FFFF21;}\n",
       ".cython.score-68 {background-color: #FFFF20;}\n",
       ".cython.score-69 {background-color: #FFFF20;}\n",
       ".cython.score-70 {background-color: #FFFF1f;}\n",
       ".cython.score-71 {background-color: #FFFF1f;}\n",
       ".cython.score-72 {background-color: #FFFF1f;}\n",
       ".cython.score-73 {background-color: #FFFF1e;}\n",
       ".cython.score-74 {background-color: #FFFF1e;}\n",
       ".cython.score-75 {background-color: #FFFF1e;}\n",
       ".cython.score-76 {background-color: #FFFF1d;}\n",
       ".cython.score-77 {background-color: #FFFF1d;}\n",
       ".cython.score-78 {background-color: #FFFF1c;}\n",
       ".cython.score-79 {background-color: #FFFF1c;}\n",
       ".cython.score-80 {background-color: #FFFF1c;}\n",
       ".cython.score-81 {background-color: #FFFF1c;}\n",
       ".cython.score-82 {background-color: #FFFF1b;}\n",
       ".cython.score-83 {background-color: #FFFF1b;}\n",
       ".cython.score-84 {background-color: #FFFF1b;}\n",
       ".cython.score-85 {background-color: #FFFF1a;}\n",
       ".cython.score-86 {background-color: #FFFF1a;}\n",
       ".cython.score-87 {background-color: #FFFF1a;}\n",
       ".cython.score-88 {background-color: #FFFF1a;}\n",
       ".cython.score-89 {background-color: #FFFF19;}\n",
       ".cython.score-90 {background-color: #FFFF19;}\n",
       ".cython.score-91 {background-color: #FFFF19;}\n",
       ".cython.score-92 {background-color: #FFFF19;}\n",
       ".cython.score-93 {background-color: #FFFF18;}\n",
       ".cython.score-94 {background-color: #FFFF18;}\n",
       ".cython.score-95 {background-color: #FFFF18;}\n",
       ".cython.score-96 {background-color: #FFFF18;}\n",
       ".cython.score-97 {background-color: #FFFF17;}\n",
       ".cython.score-98 {background-color: #FFFF17;}\n",
       ".cython.score-99 {background-color: #FFFF17;}\n",
       ".cython.score-100 {background-color: #FFFF17;}\n",
       ".cython.score-101 {background-color: #FFFF16;}\n",
       ".cython.score-102 {background-color: #FFFF16;}\n",
       ".cython.score-103 {background-color: #FFFF16;}\n",
       ".cython.score-104 {background-color: #FFFF16;}\n",
       ".cython.score-105 {background-color: #FFFF16;}\n",
       ".cython.score-106 {background-color: #FFFF15;}\n",
       ".cython.score-107 {background-color: #FFFF15;}\n",
       ".cython.score-108 {background-color: #FFFF15;}\n",
       ".cython.score-109 {background-color: #FFFF15;}\n",
       ".cython.score-110 {background-color: #FFFF15;}\n",
       ".cython.score-111 {background-color: #FFFF15;}\n",
       ".cython.score-112 {background-color: #FFFF14;}\n",
       ".cython.score-113 {background-color: #FFFF14;}\n",
       ".cython.score-114 {background-color: #FFFF14;}\n",
       ".cython.score-115 {background-color: #FFFF14;}\n",
       ".cython.score-116 {background-color: #FFFF14;}\n",
       ".cython.score-117 {background-color: #FFFF14;}\n",
       ".cython.score-118 {background-color: #FFFF13;}\n",
       ".cython.score-119 {background-color: #FFFF13;}\n",
       ".cython.score-120 {background-color: #FFFF13;}\n",
       ".cython.score-121 {background-color: #FFFF13;}\n",
       ".cython.score-122 {background-color: #FFFF13;}\n",
       ".cython.score-123 {background-color: #FFFF13;}\n",
       ".cython.score-124 {background-color: #FFFF13;}\n",
       ".cython.score-125 {background-color: #FFFF12;}\n",
       ".cython.score-126 {background-color: #FFFF12;}\n",
       ".cython.score-127 {background-color: #FFFF12;}\n",
       ".cython.score-128 {background-color: #FFFF12;}\n",
       ".cython.score-129 {background-color: #FFFF12;}\n",
       ".cython.score-130 {background-color: #FFFF12;}\n",
       ".cython.score-131 {background-color: #FFFF12;}\n",
       ".cython.score-132 {background-color: #FFFF11;}\n",
       ".cython.score-133 {background-color: #FFFF11;}\n",
       ".cython.score-134 {background-color: #FFFF11;}\n",
       ".cython.score-135 {background-color: #FFFF11;}\n",
       ".cython.score-136 {background-color: #FFFF11;}\n",
       ".cython.score-137 {background-color: #FFFF11;}\n",
       ".cython.score-138 {background-color: #FFFF11;}\n",
       ".cython.score-139 {background-color: #FFFF11;}\n",
       ".cython.score-140 {background-color: #FFFF11;}\n",
       ".cython.score-141 {background-color: #FFFF10;}\n",
       ".cython.score-142 {background-color: #FFFF10;}\n",
       ".cython.score-143 {background-color: #FFFF10;}\n",
       ".cython.score-144 {background-color: #FFFF10;}\n",
       ".cython.score-145 {background-color: #FFFF10;}\n",
       ".cython.score-146 {background-color: #FFFF10;}\n",
       ".cython.score-147 {background-color: #FFFF10;}\n",
       ".cython.score-148 {background-color: #FFFF10;}\n",
       ".cython.score-149 {background-color: #FFFF10;}\n",
       ".cython.score-150 {background-color: #FFFF0f;}\n",
       ".cython.score-151 {background-color: #FFFF0f;}\n",
       ".cython.score-152 {background-color: #FFFF0f;}\n",
       ".cython.score-153 {background-color: #FFFF0f;}\n",
       ".cython.score-154 {background-color: #FFFF0f;}\n",
       ".cython.score-155 {background-color: #FFFF0f;}\n",
       ".cython.score-156 {background-color: #FFFF0f;}\n",
       ".cython.score-157 {background-color: #FFFF0f;}\n",
       ".cython.score-158 {background-color: #FFFF0f;}\n",
       ".cython.score-159 {background-color: #FFFF0f;}\n",
       ".cython.score-160 {background-color: #FFFF0f;}\n",
       ".cython.score-161 {background-color: #FFFF0e;}\n",
       ".cython.score-162 {background-color: #FFFF0e;}\n",
       ".cython.score-163 {background-color: #FFFF0e;}\n",
       ".cython.score-164 {background-color: #FFFF0e;}\n",
       ".cython.score-165 {background-color: #FFFF0e;}\n",
       ".cython.score-166 {background-color: #FFFF0e;}\n",
       ".cython.score-167 {background-color: #FFFF0e;}\n",
       ".cython.score-168 {background-color: #FFFF0e;}\n",
       ".cython.score-169 {background-color: #FFFF0e;}\n",
       ".cython.score-170 {background-color: #FFFF0e;}\n",
       ".cython.score-171 {background-color: #FFFF0e;}\n",
       ".cython.score-172 {background-color: #FFFF0e;}\n",
       ".cython.score-173 {background-color: #FFFF0d;}\n",
       ".cython.score-174 {background-color: #FFFF0d;}\n",
       ".cython.score-175 {background-color: #FFFF0d;}\n",
       ".cython.score-176 {background-color: #FFFF0d;}\n",
       ".cython.score-177 {background-color: #FFFF0d;}\n",
       ".cython.score-178 {background-color: #FFFF0d;}\n",
       ".cython.score-179 {background-color: #FFFF0d;}\n",
       ".cython.score-180 {background-color: #FFFF0d;}\n",
       ".cython.score-181 {background-color: #FFFF0d;}\n",
       ".cython.score-182 {background-color: #FFFF0d;}\n",
       ".cython.score-183 {background-color: #FFFF0d;}\n",
       ".cython.score-184 {background-color: #FFFF0d;}\n",
       ".cython.score-185 {background-color: #FFFF0d;}\n",
       ".cython.score-186 {background-color: #FFFF0d;}\n",
       ".cython.score-187 {background-color: #FFFF0c;}\n",
       ".cython.score-188 {background-color: #FFFF0c;}\n",
       ".cython.score-189 {background-color: #FFFF0c;}\n",
       ".cython.score-190 {background-color: #FFFF0c;}\n",
       ".cython.score-191 {background-color: #FFFF0c;}\n",
       ".cython.score-192 {background-color: #FFFF0c;}\n",
       ".cython.score-193 {background-color: #FFFF0c;}\n",
       ".cython.score-194 {background-color: #FFFF0c;}\n",
       ".cython.score-195 {background-color: #FFFF0c;}\n",
       ".cython.score-196 {background-color: #FFFF0c;}\n",
       ".cython.score-197 {background-color: #FFFF0c;}\n",
       ".cython.score-198 {background-color: #FFFF0c;}\n",
       ".cython.score-199 {background-color: #FFFF0c;}\n",
       ".cython.score-200 {background-color: #FFFF0c;}\n",
       ".cython.score-201 {background-color: #FFFF0c;}\n",
       ".cython.score-202 {background-color: #FFFF0c;}\n",
       ".cython.score-203 {background-color: #FFFF0b;}\n",
       ".cython.score-204 {background-color: #FFFF0b;}\n",
       ".cython.score-205 {background-color: #FFFF0b;}\n",
       ".cython.score-206 {background-color: #FFFF0b;}\n",
       ".cython.score-207 {background-color: #FFFF0b;}\n",
       ".cython.score-208 {background-color: #FFFF0b;}\n",
       ".cython.score-209 {background-color: #FFFF0b;}\n",
       ".cython.score-210 {background-color: #FFFF0b;}\n",
       ".cython.score-211 {background-color: #FFFF0b;}\n",
       ".cython.score-212 {background-color: #FFFF0b;}\n",
       ".cython.score-213 {background-color: #FFFF0b;}\n",
       ".cython.score-214 {background-color: #FFFF0b;}\n",
       ".cython.score-215 {background-color: #FFFF0b;}\n",
       ".cython.score-216 {background-color: #FFFF0b;}\n",
       ".cython.score-217 {background-color: #FFFF0b;}\n",
       ".cython.score-218 {background-color: #FFFF0b;}\n",
       ".cython.score-219 {background-color: #FFFF0b;}\n",
       ".cython.score-220 {background-color: #FFFF0b;}\n",
       ".cython.score-221 {background-color: #FFFF0b;}\n",
       ".cython.score-222 {background-color: #FFFF0a;}\n",
       ".cython.score-223 {background-color: #FFFF0a;}\n",
       ".cython.score-224 {background-color: #FFFF0a;}\n",
       ".cython.score-225 {background-color: #FFFF0a;}\n",
       ".cython.score-226 {background-color: #FFFF0a;}\n",
       ".cython.score-227 {background-color: #FFFF0a;}\n",
       ".cython.score-228 {background-color: #FFFF0a;}\n",
       ".cython.score-229 {background-color: #FFFF0a;}\n",
       ".cython.score-230 {background-color: #FFFF0a;}\n",
       ".cython.score-231 {background-color: #FFFF0a;}\n",
       ".cython.score-232 {background-color: #FFFF0a;}\n",
       ".cython.score-233 {background-color: #FFFF0a;}\n",
       ".cython.score-234 {background-color: #FFFF0a;}\n",
       ".cython.score-235 {background-color: #FFFF0a;}\n",
       ".cython.score-236 {background-color: #FFFF0a;}\n",
       ".cython.score-237 {background-color: #FFFF0a;}\n",
       ".cython.score-238 {background-color: #FFFF0a;}\n",
       ".cython.score-239 {background-color: #FFFF0a;}\n",
       ".cython.score-240 {background-color: #FFFF0a;}\n",
       ".cython.score-241 {background-color: #FFFF0a;}\n",
       ".cython.score-242 {background-color: #FFFF0a;}\n",
       ".cython.score-243 {background-color: #FFFF0a;}\n",
       ".cython.score-244 {background-color: #FFFF0a;}\n",
       ".cython.score-245 {background-color: #FFFF0a;}\n",
       ".cython.score-246 {background-color: #FFFF09;}\n",
       ".cython.score-247 {background-color: #FFFF09;}\n",
       ".cython.score-248 {background-color: #FFFF09;}\n",
       ".cython.score-249 {background-color: #FFFF09;}\n",
       ".cython.score-250 {background-color: #FFFF09;}\n",
       ".cython.score-251 {background-color: #FFFF09;}\n",
       ".cython.score-252 {background-color: #FFFF09;}\n",
       ".cython.score-253 {background-color: #FFFF09;}\n",
       ".cython.score-254 {background-color: #FFFF09;}\n",
       ".cython .hll { background-color: #ffffcc }\n",
       ".cython  { background: #f8f8f8; }\n",
       ".cython .c { color: #408080; font-style: italic } /* Comment */\n",
       ".cython .err { border: 1px solid #FF0000 } /* Error */\n",
       ".cython .k { color: #008000; font-weight: bold } /* Keyword */\n",
       ".cython .o { color: #666666 } /* Operator */\n",
       ".cython .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n",
       ".cython .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n",
       ".cython .cp { color: #BC7A00 } /* Comment.Preproc */\n",
       ".cython .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n",
       ".cython .c1 { color: #408080; font-style: italic } /* Comment.Single */\n",
       ".cython .cs { color: #408080; font-style: italic } /* Comment.Special */\n",
       ".cython .gd { color: #A00000 } /* Generic.Deleted */\n",
       ".cython .ge { font-style: italic } /* Generic.Emph */\n",
       ".cython .gr { color: #FF0000 } /* Generic.Error */\n",
       ".cython .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n",
       ".cython .gi { color: #00A000 } /* Generic.Inserted */\n",
       ".cython .go { color: #888888 } /* Generic.Output */\n",
       ".cython .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n",
       ".cython .gs { font-weight: bold } /* Generic.Strong */\n",
       ".cython .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n",
       ".cython .gt { color: #0044DD } /* Generic.Traceback */\n",
       ".cython .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n",
       ".cython .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n",
       ".cython .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n",
       ".cython .kp { color: #008000 } /* Keyword.Pseudo */\n",
       ".cython .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n",
       ".cython .kt { color: #B00040 } /* Keyword.Type */\n",
       ".cython .m { color: #666666 } /* Literal.Number */\n",
       ".cython .s { color: #BA2121 } /* Literal.String */\n",
       ".cython .na { color: #7D9029 } /* Name.Attribute */\n",
       ".cython .nb { color: #008000 } /* Name.Builtin */\n",
       ".cython .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n",
       ".cython .no { color: #880000 } /* Name.Constant */\n",
       ".cython .nd { color: #AA22FF } /* Name.Decorator */\n",
       ".cython .ni { color: #999999; font-weight: bold } /* Name.Entity */\n",
       ".cython .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n",
       ".cython .nf { color: #0000FF } /* Name.Function */\n",
       ".cython .nl { color: #A0A000 } /* Name.Label */\n",
       ".cython .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n",
       ".cython .nt { color: #008000; font-weight: bold } /* Name.Tag */\n",
       ".cython .nv { color: #19177C } /* Name.Variable */\n",
       ".cython .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n",
       ".cython .w { color: #bbbbbb } /* Text.Whitespace */\n",
       ".cython .mb { color: #666666 } /* Literal.Number.Bin */\n",
       ".cython .mf { color: #666666 } /* Literal.Number.Float */\n",
       ".cython .mh { color: #666666 } /* Literal.Number.Hex */\n",
       ".cython .mi { color: #666666 } /* Literal.Number.Integer */\n",
       ".cython .mo { color: #666666 } /* Literal.Number.Oct */\n",
       ".cython .sa { color: #BA2121 } /* Literal.String.Affix */\n",
       ".cython .sb { color: #BA2121 } /* Literal.String.Backtick */\n",
       ".cython .sc { color: #BA2121 } /* Literal.String.Char */\n",
       ".cython .dl { color: #BA2121 } /* Literal.String.Delimiter */\n",
       ".cython .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n",
       ".cython .s2 { color: #BA2121 } /* Literal.String.Double */\n",
       ".cython .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n",
       ".cython .sh { color: #BA2121 } /* Literal.String.Heredoc */\n",
       ".cython .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n",
       ".cython .sx { color: #008000 } /* Literal.String.Other */\n",
       ".cython .sr { color: #BB6688 } /* Literal.String.Regex */\n",
       ".cython .s1 { color: #BA2121 } /* Literal.String.Single */\n",
       ".cython .ss { color: #19177C } /* Literal.String.Symbol */\n",
       ".cython .bp { color: #008000 } /* Name.Builtin.Pseudo */\n",
       ".cython .fm { color: #0000FF } /* Name.Function.Magic */\n",
       ".cython .vc { color: #19177C } /* Name.Variable.Class */\n",
       ".cython .vg { color: #19177C } /* Name.Variable.Global */\n",
       ".cython .vi { color: #19177C } /* Name.Variable.Instance */\n",
       ".cython .vm { color: #19177C } /* Name.Variable.Magic */\n",
       ".cython .il { color: #666666 } /* Literal.Number.Integer.Long */\n",
       "    </style>\n",
       "</head>\n",
       "<body class=\"cython\">\n",
       "<p><span style=\"border-bottom: solid 1px grey;\">Generated by Cython 0.29.20</span></p>\n",
       "<p>\n",
       "    <span style=\"background-color: #FFFF00\">Yellow lines</span> hint at Python interaction.<br />\n",
       "    Click on a line that starts with a \"<code>+</code>\" to see the C code that Cython generated for it.\n",
       "</p>\n",
       "<div class=\"cython\"><pre class=\"cython line score-8\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">1</span>: <span class=\"k\">import</span> <span class=\"nn\">random</span></pre>\n",
       "<pre class='cython code score-8 '>  __pyx_t_1 = <span class='pyx_c_api'>__Pyx_Import</span>(__pyx_n_s_random, 0, 0);<span class='error_goto'> if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_1);\n",
       "  if (<span class='py_c_api'>PyDict_SetItem</span>(__pyx_d, __pyx_n_s_random, __pyx_t_1) &lt; 0) <span class='error_goto'>__PYX_ERR(0, 1, __pyx_L1_error)</span>\n",
       "  <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_1); __pyx_t_1 = 0;\n",
       "</pre><pre class=\"cython line score-26\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">2</span>: <span class=\"k\">def</span> <span class=\"nf\">average_cy1</span><span class=\"p\">(</span><span class=\"nb\">int</span> <span class=\"n\">n</span><span class=\"p\">):</span></pre>\n",
       "<pre class='cython code score-26 '>/* Python wrapper */\n",
       "static PyObject *__pyx_pw_46_cython_magic_df7795ef4529753db07280ca67f4c5d6_1average_cy1(PyObject *__pyx_self, PyObject *__pyx_arg_n); /*proto*/\n",
       "static PyMethodDef __pyx_mdef_46_cython_magic_df7795ef4529753db07280ca67f4c5d6_1average_cy1 = {\"average_cy1\", (PyCFunction)__pyx_pw_46_cython_magic_df7795ef4529753db07280ca67f4c5d6_1average_cy1, METH_O, 0};\n",
       "static PyObject *__pyx_pw_46_cython_magic_df7795ef4529753db07280ca67f4c5d6_1average_cy1(PyObject *__pyx_self, PyObject *__pyx_arg_n) {\n",
       "  int __pyx_v_n;\n",
       "  PyObject *__pyx_r = 0;\n",
       "  <span class='refnanny'>__Pyx_RefNannyDeclarations</span>\n",
       "  <span class='refnanny'>__Pyx_RefNannySetupContext</span>(\"average_cy1 (wrapper)\", 0);\n",
       "  assert(__pyx_arg_n); {\n",
       "    __pyx_v_n = <span class='pyx_c_api'>__Pyx_PyInt_As_int</span>(__pyx_arg_n); if (unlikely((__pyx_v_n == (int)-1) &amp;&amp; <span class='py_c_api'>PyErr_Occurred</span>())) <span class='error_goto'>__PYX_ERR(0, 2, __pyx_L3_error)</span>\n",
       "  }\n",
       "  goto __pyx_L4_argument_unpacking_done;\n",
       "  __pyx_L3_error:;\n",
       "  <span class='pyx_c_api'>__Pyx_AddTraceback</span>(\"_cython_magic_df7795ef4529753db07280ca67f4c5d6.average_cy1\", __pyx_clineno, __pyx_lineno, __pyx_filename);\n",
       "  <span class='refnanny'>__Pyx_RefNannyFinishContext</span>();\n",
       "  return NULL;\n",
       "  __pyx_L4_argument_unpacking_done:;\n",
       "  __pyx_r = __pyx_pf_46_cython_magic_df7795ef4529753db07280ca67f4c5d6_average_cy1(__pyx_self, ((int)__pyx_v_n));\n",
       "  int __pyx_lineno = 0;\n",
       "  const char *__pyx_filename = NULL;\n",
       "  int __pyx_clineno = 0;\n",
       "\n",
       "  /* function exit code */\n",
       "  <span class='refnanny'>__Pyx_RefNannyFinishContext</span>();\n",
       "  return __pyx_r;\n",
       "}\n",
       "\n",
       "static PyObject *__pyx_pf_46_cython_magic_df7795ef4529753db07280ca67f4c5d6_average_cy1(CYTHON_UNUSED PyObject *__pyx_self, int __pyx_v_n) {\n",
       "  CYTHON_UNUSED int __pyx_v_i;\n",
       "  float __pyx_v_s;\n",
       "  PyObject *__pyx_r = NULL;\n",
       "  <span class='refnanny'>__Pyx_RefNannyDeclarations</span>\n",
       "  <span class='refnanny'>__Pyx_RefNannySetupContext</span>(\"average_cy1\", 0);\n",
       "/* … */\n",
       "  /* function exit code */\n",
       "  __pyx_L1_error:;\n",
       "  <span class='pyx_macro_api'>__Pyx_XDECREF</span>(__pyx_t_4);\n",
       "  <span class='pyx_macro_api'>__Pyx_XDECREF</span>(__pyx_t_5);\n",
       "  <span class='pyx_macro_api'>__Pyx_XDECREF</span>(__pyx_t_6);\n",
       "  <span class='pyx_macro_api'>__Pyx_XDECREF</span>(__pyx_t_7);\n",
       "  <span class='pyx_c_api'>__Pyx_AddTraceback</span>(\"_cython_magic_df7795ef4529753db07280ca67f4c5d6.average_cy1\", __pyx_clineno, __pyx_lineno, __pyx_filename);\n",
       "  __pyx_r = NULL;\n",
       "  __pyx_L0:;\n",
       "  <span class='refnanny'>__Pyx_XGIVEREF</span>(__pyx_r);\n",
       "  <span class='refnanny'>__Pyx_RefNannyFinishContext</span>();\n",
       "  return __pyx_r;\n",
       "}\n",
       "/* … */\n",
       "  __pyx_tuple_ = <span class='py_c_api'>PyTuple_Pack</span>(4, __pyx_n_s_n, __pyx_n_s_n, __pyx_n_s_i, __pyx_n_s_s);<span class='error_goto'> if (unlikely(!__pyx_tuple_)) __PYX_ERR(0, 2, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_tuple_);\n",
       "  <span class='refnanny'>__Pyx_GIVEREF</span>(__pyx_tuple_);\n",
       "/* … */\n",
       "  __pyx_t_1 = PyCFunction_NewEx(&amp;__pyx_mdef_46_cython_magic_df7795ef4529753db07280ca67f4c5d6_1average_cy1, NULL, __pyx_n_s_cython_magic_df7795ef4529753db0);<span class='error_goto'> if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_1);\n",
       "  if (<span class='py_c_api'>PyDict_SetItem</span>(__pyx_d, __pyx_n_s_average_cy1, __pyx_t_1) &lt; 0) <span class='error_goto'>__PYX_ERR(0, 2, __pyx_L1_error)</span>\n",
       "  <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_1); __pyx_t_1 = 0;\n",
       "</pre><pre class=\"cython line score-0\">&#xA0;<span class=\"\">3</span>:     <span class=\"k\">cdef</span> <span class=\"kt\">int</span> <span class=\"nf\">i</span></pre>\n",
       "<pre class=\"cython line score-0\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">4</span>:     <span class=\"k\">cdef</span> <span class=\"kt\">float</span> <span class=\"nf\">s</span> <span class=\"o\">=</span> <span class=\"mf\">0</span></pre>\n",
       "<pre class='cython code score-0 '>  __pyx_v_s = 0.0;\n",
       "</pre><pre class=\"cython line score-0\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">5</span>:     <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">n</span><span class=\"p\">):</span></pre>\n",
       "<pre class='cython code score-0 '>  __pyx_t_1 = __pyx_v_n;\n",
       "  __pyx_t_2 = __pyx_t_1;\n",
       "  for (__pyx_t_3 = 0; __pyx_t_3 &lt; __pyx_t_2; __pyx_t_3+=1) {\n",
       "    __pyx_v_i = __pyx_t_3;\n",
       "</pre><pre class=\"cython line score-44\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">6</span>:         <span class=\"n\">s</span> <span class=\"o\">+=</span> <span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"p\">()</span></pre>\n",
       "<pre class='cython code score-44 '>    __pyx_t_4 = <span class='py_c_api'>PyFloat_FromDouble</span>(__pyx_v_s);<span class='error_goto'> if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 6, __pyx_L1_error)</span>\n",
       "    <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_4);\n",
       "    <span class='pyx_c_api'>__Pyx_GetModuleGlobalName</span>(__pyx_t_6, __pyx_n_s_random);<span class='error_goto'> if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 6, __pyx_L1_error)</span>\n",
       "    <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_6);\n",
       "    __pyx_t_7 = <span class='pyx_c_api'>__Pyx_PyObject_GetAttrStr</span>(__pyx_t_6, __pyx_n_s_random);<span class='error_goto'> if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 6, __pyx_L1_error)</span>\n",
       "    <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_7);\n",
       "    <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_6); __pyx_t_6 = 0;\n",
       "    __pyx_t_6 = NULL;\n",
       "    if (CYTHON_UNPACK_METHODS &amp;&amp; unlikely(<span class='py_c_api'>PyMethod_Check</span>(__pyx_t_7))) {\n",
       "      __pyx_t_6 = <span class='py_macro_api'>PyMethod_GET_SELF</span>(__pyx_t_7);\n",
       "      if (likely(__pyx_t_6)) {\n",
       "        PyObject* function = <span class='py_macro_api'>PyMethod_GET_FUNCTION</span>(__pyx_t_7);\n",
       "        <span class='pyx_macro_api'>__Pyx_INCREF</span>(__pyx_t_6);\n",
       "        <span class='pyx_macro_api'>__Pyx_INCREF</span>(function);\n",
       "        <span class='pyx_macro_api'>__Pyx_DECREF_SET</span>(__pyx_t_7, function);\n",
       "      }\n",
       "    }\n",
       "    __pyx_t_5 = (__pyx_t_6) ? <span class='pyx_c_api'>__Pyx_PyObject_CallOneArg</span>(__pyx_t_7, __pyx_t_6) : <span class='pyx_c_api'>__Pyx_PyObject_CallNoArg</span>(__pyx_t_7);\n",
       "    <span class='pyx_macro_api'>__Pyx_XDECREF</span>(__pyx_t_6); __pyx_t_6 = 0;\n",
       "    if (unlikely(!__pyx_t_5)) <span class='error_goto'>__PYX_ERR(0, 6, __pyx_L1_error)</span>\n",
       "    <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_5);\n",
       "    <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_7); __pyx_t_7 = 0;\n",
       "    __pyx_t_7 = <span class='py_c_api'>PyNumber_InPlaceAdd</span>(__pyx_t_4, __pyx_t_5);<span class='error_goto'> if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 6, __pyx_L1_error)</span>\n",
       "    <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_7);\n",
       "    <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_4); __pyx_t_4 = 0;\n",
       "    <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_5); __pyx_t_5 = 0;\n",
       "    __pyx_t_8 = __pyx_<span class='py_c_api'>PyFloat_AsFloat</span>(__pyx_t_7); if (unlikely((__pyx_t_8 == (float)-1) &amp;&amp; <span class='py_c_api'>PyErr_Occurred</span>())) <span class='error_goto'>__PYX_ERR(0, 6, __pyx_L1_error)</span>\n",
       "    <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_7); __pyx_t_7 = 0;\n",
       "    __pyx_v_s = __pyx_t_8;\n",
       "  }\n",
       "</pre><pre class=\"cython line score-11\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">7</span>:     <span class=\"k\">return</span> <span class=\"n\">s</span> <span class=\"o\">/</span> <span class=\"n\">n</span></pre>\n",
       "<pre class='cython code score-11 '>  <span class='pyx_macro_api'>__Pyx_XDECREF</span>(__pyx_r);\n",
       "  if (unlikely(__pyx_v_n == 0)) {\n",
       "    <span class='py_c_api'>PyErr_SetString</span>(PyExc_ZeroDivisionError, \"float division\");\n",
       "    <span class='error_goto'>__PYX_ERR(0, 7, __pyx_L1_error)</span>\n",
       "  }\n",
       "  __pyx_t_7 = <span class='py_c_api'>PyFloat_FromDouble</span>((__pyx_v_s / ((float)__pyx_v_n)));<span class='error_goto'> if (unlikely(!__pyx_t_7)) __PYX_ERR(0, 7, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_7);\n",
       "  __pyx_r = __pyx_t_7;\n",
       "  __pyx_t_7 = 0;\n",
       "  goto __pyx_L0;\n",
       "</pre></div></body></html>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%%cython -a\n",
    "import random  \n",
    "def average_cy1(int n):  \n",
    "    cdef int i  \n",
    "    cdef float s = 0  \n",
    "    for i in range(n):\n",
    "        s += random.random()\n",
    "    return s / n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 619 ms, sys: 2.3 ms, total: 622 ms\n",
      "Wall time: 621 ms\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "0.49999159574508667"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time average_cy1(n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "619 ms ± 16 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
     ]
    }
   ],
   "source": [
    "%timeit average_cy1(n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.6792964339256287\n",
      "0.934692919254303\n",
      "0.3835020661354065\n",
      "0.5194163918495178\n",
      "0.8309653401374817\n"
     ]
    }
   ],
   "source": [
    "%%cython\n",
    "from libc.stdlib cimport rand  \n",
    "cdef extern from 'limits.h':  \n",
    "    int INT_MAX  \n",
    "cdef int i\n",
    "cdef float rn\n",
    "for i in range(5):\n",
    "    rn = rand() / INT_MAX  \n",
    "    print(rn)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<!DOCTYPE html>\n",
       "<!-- Generated by Cython 0.29.20 -->\n",
       "<html>\n",
       "<head>\n",
       "    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n",
       "    <title>Cython: _cython_magic_553e34652a1f7de3ae3551b1aad8ebdd.pyx</title>\n",
       "    <style type=\"text/css\">\n",
       "    \n",
       "body.cython { font-family: courier; font-size: 12; }\n",
       "\n",
       ".cython.tag  {  }\n",
       ".cython.line { margin: 0em }\n",
       ".cython.code { font-size: 9; color: #444444; display: none; margin: 0px 0px 0px 8px; border-left: 8px none; }\n",
       "\n",
       ".cython.line .run { background-color: #B0FFB0; }\n",
       ".cython.line .mis { background-color: #FFB0B0; }\n",
       ".cython.code.run  { border-left: 8px solid #B0FFB0; }\n",
       ".cython.code.mis  { border-left: 8px solid #FFB0B0; }\n",
       "\n",
       ".cython.code .py_c_api  { color: red; }\n",
       ".cython.code .py_macro_api  { color: #FF7000; }\n",
       ".cython.code .pyx_c_api  { color: #FF3000; }\n",
       ".cython.code .pyx_macro_api  { color: #FF7000; }\n",
       ".cython.code .refnanny  { color: #FFA000; }\n",
       ".cython.code .trace  { color: #FFA000; }\n",
       ".cython.code .error_goto  { color: #FFA000; }\n",
       "\n",
       ".cython.code .coerce  { color: #008000; border: 1px dotted #008000 }\n",
       ".cython.code .py_attr { color: #FF0000; font-weight: bold; }\n",
       ".cython.code .c_attr  { color: #0000FF; }\n",
       ".cython.code .py_call { color: #FF0000; font-weight: bold; }\n",
       ".cython.code .c_call  { color: #0000FF; }\n",
       "\n",
       ".cython.score-0 {background-color: #FFFFff;}\n",
       ".cython.score-1 {background-color: #FFFFe7;}\n",
       ".cython.score-2 {background-color: #FFFFd4;}\n",
       ".cython.score-3 {background-color: #FFFFc4;}\n",
       ".cython.score-4 {background-color: #FFFFb6;}\n",
       ".cython.score-5 {background-color: #FFFFaa;}\n",
       ".cython.score-6 {background-color: #FFFF9f;}\n",
       ".cython.score-7 {background-color: #FFFF96;}\n",
       ".cython.score-8 {background-color: #FFFF8d;}\n",
       ".cython.score-9 {background-color: #FFFF86;}\n",
       ".cython.score-10 {background-color: #FFFF7f;}\n",
       ".cython.score-11 {background-color: #FFFF79;}\n",
       ".cython.score-12 {background-color: #FFFF73;}\n",
       ".cython.score-13 {background-color: #FFFF6e;}\n",
       ".cython.score-14 {background-color: #FFFF6a;}\n",
       ".cython.score-15 {background-color: #FFFF66;}\n",
       ".cython.score-16 {background-color: #FFFF62;}\n",
       ".cython.score-17 {background-color: #FFFF5e;}\n",
       ".cython.score-18 {background-color: #FFFF5b;}\n",
       ".cython.score-19 {background-color: #FFFF57;}\n",
       ".cython.score-20 {background-color: #FFFF55;}\n",
       ".cython.score-21 {background-color: #FFFF52;}\n",
       ".cython.score-22 {background-color: #FFFF4f;}\n",
       ".cython.score-23 {background-color: #FFFF4d;}\n",
       ".cython.score-24 {background-color: #FFFF4b;}\n",
       ".cython.score-25 {background-color: #FFFF48;}\n",
       ".cython.score-26 {background-color: #FFFF46;}\n",
       ".cython.score-27 {background-color: #FFFF44;}\n",
       ".cython.score-28 {background-color: #FFFF43;}\n",
       ".cython.score-29 {background-color: #FFFF41;}\n",
       ".cython.score-30 {background-color: #FFFF3f;}\n",
       ".cython.score-31 {background-color: #FFFF3e;}\n",
       ".cython.score-32 {background-color: #FFFF3c;}\n",
       ".cython.score-33 {background-color: #FFFF3b;}\n",
       ".cython.score-34 {background-color: #FFFF39;}\n",
       ".cython.score-35 {background-color: #FFFF38;}\n",
       ".cython.score-36 {background-color: #FFFF37;}\n",
       ".cython.score-37 {background-color: #FFFF36;}\n",
       ".cython.score-38 {background-color: #FFFF35;}\n",
       ".cython.score-39 {background-color: #FFFF34;}\n",
       ".cython.score-40 {background-color: #FFFF33;}\n",
       ".cython.score-41 {background-color: #FFFF32;}\n",
       ".cython.score-42 {background-color: #FFFF31;}\n",
       ".cython.score-43 {background-color: #FFFF30;}\n",
       ".cython.score-44 {background-color: #FFFF2f;}\n",
       ".cython.score-45 {background-color: #FFFF2e;}\n",
       ".cython.score-46 {background-color: #FFFF2d;}\n",
       ".cython.score-47 {background-color: #FFFF2c;}\n",
       ".cython.score-48 {background-color: #FFFF2b;}\n",
       ".cython.score-49 {background-color: #FFFF2b;}\n",
       ".cython.score-50 {background-color: #FFFF2a;}\n",
       ".cython.score-51 {background-color: #FFFF29;}\n",
       ".cython.score-52 {background-color: #FFFF29;}\n",
       ".cython.score-53 {background-color: #FFFF28;}\n",
       ".cython.score-54 {background-color: #FFFF27;}\n",
       ".cython.score-55 {background-color: #FFFF27;}\n",
       ".cython.score-56 {background-color: #FFFF26;}\n",
       ".cython.score-57 {background-color: #FFFF26;}\n",
       ".cython.score-58 {background-color: #FFFF25;}\n",
       ".cython.score-59 {background-color: #FFFF24;}\n",
       ".cython.score-60 {background-color: #FFFF24;}\n",
       ".cython.score-61 {background-color: #FFFF23;}\n",
       ".cython.score-62 {background-color: #FFFF23;}\n",
       ".cython.score-63 {background-color: #FFFF22;}\n",
       ".cython.score-64 {background-color: #FFFF22;}\n",
       ".cython.score-65 {background-color: #FFFF22;}\n",
       ".cython.score-66 {background-color: #FFFF21;}\n",
       ".cython.score-67 {background-color: #FFFF21;}\n",
       ".cython.score-68 {background-color: #FFFF20;}\n",
       ".cython.score-69 {background-color: #FFFF20;}\n",
       ".cython.score-70 {background-color: #FFFF1f;}\n",
       ".cython.score-71 {background-color: #FFFF1f;}\n",
       ".cython.score-72 {background-color: #FFFF1f;}\n",
       ".cython.score-73 {background-color: #FFFF1e;}\n",
       ".cython.score-74 {background-color: #FFFF1e;}\n",
       ".cython.score-75 {background-color: #FFFF1e;}\n",
       ".cython.score-76 {background-color: #FFFF1d;}\n",
       ".cython.score-77 {background-color: #FFFF1d;}\n",
       ".cython.score-78 {background-color: #FFFF1c;}\n",
       ".cython.score-79 {background-color: #FFFF1c;}\n",
       ".cython.score-80 {background-color: #FFFF1c;}\n",
       ".cython.score-81 {background-color: #FFFF1c;}\n",
       ".cython.score-82 {background-color: #FFFF1b;}\n",
       ".cython.score-83 {background-color: #FFFF1b;}\n",
       ".cython.score-84 {background-color: #FFFF1b;}\n",
       ".cython.score-85 {background-color: #FFFF1a;}\n",
       ".cython.score-86 {background-color: #FFFF1a;}\n",
       ".cython.score-87 {background-color: #FFFF1a;}\n",
       ".cython.score-88 {background-color: #FFFF1a;}\n",
       ".cython.score-89 {background-color: #FFFF19;}\n",
       ".cython.score-90 {background-color: #FFFF19;}\n",
       ".cython.score-91 {background-color: #FFFF19;}\n",
       ".cython.score-92 {background-color: #FFFF19;}\n",
       ".cython.score-93 {background-color: #FFFF18;}\n",
       ".cython.score-94 {background-color: #FFFF18;}\n",
       ".cython.score-95 {background-color: #FFFF18;}\n",
       ".cython.score-96 {background-color: #FFFF18;}\n",
       ".cython.score-97 {background-color: #FFFF17;}\n",
       ".cython.score-98 {background-color: #FFFF17;}\n",
       ".cython.score-99 {background-color: #FFFF17;}\n",
       ".cython.score-100 {background-color: #FFFF17;}\n",
       ".cython.score-101 {background-color: #FFFF16;}\n",
       ".cython.score-102 {background-color: #FFFF16;}\n",
       ".cython.score-103 {background-color: #FFFF16;}\n",
       ".cython.score-104 {background-color: #FFFF16;}\n",
       ".cython.score-105 {background-color: #FFFF16;}\n",
       ".cython.score-106 {background-color: #FFFF15;}\n",
       ".cython.score-107 {background-color: #FFFF15;}\n",
       ".cython.score-108 {background-color: #FFFF15;}\n",
       ".cython.score-109 {background-color: #FFFF15;}\n",
       ".cython.score-110 {background-color: #FFFF15;}\n",
       ".cython.score-111 {background-color: #FFFF15;}\n",
       ".cython.score-112 {background-color: #FFFF14;}\n",
       ".cython.score-113 {background-color: #FFFF14;}\n",
       ".cython.score-114 {background-color: #FFFF14;}\n",
       ".cython.score-115 {background-color: #FFFF14;}\n",
       ".cython.score-116 {background-color: #FFFF14;}\n",
       ".cython.score-117 {background-color: #FFFF14;}\n",
       ".cython.score-118 {background-color: #FFFF13;}\n",
       ".cython.score-119 {background-color: #FFFF13;}\n",
       ".cython.score-120 {background-color: #FFFF13;}\n",
       ".cython.score-121 {background-color: #FFFF13;}\n",
       ".cython.score-122 {background-color: #FFFF13;}\n",
       ".cython.score-123 {background-color: #FFFF13;}\n",
       ".cython.score-124 {background-color: #FFFF13;}\n",
       ".cython.score-125 {background-color: #FFFF12;}\n",
       ".cython.score-126 {background-color: #FFFF12;}\n",
       ".cython.score-127 {background-color: #FFFF12;}\n",
       ".cython.score-128 {background-color: #FFFF12;}\n",
       ".cython.score-129 {background-color: #FFFF12;}\n",
       ".cython.score-130 {background-color: #FFFF12;}\n",
       ".cython.score-131 {background-color: #FFFF12;}\n",
       ".cython.score-132 {background-color: #FFFF11;}\n",
       ".cython.score-133 {background-color: #FFFF11;}\n",
       ".cython.score-134 {background-color: #FFFF11;}\n",
       ".cython.score-135 {background-color: #FFFF11;}\n",
       ".cython.score-136 {background-color: #FFFF11;}\n",
       ".cython.score-137 {background-color: #FFFF11;}\n",
       ".cython.score-138 {background-color: #FFFF11;}\n",
       ".cython.score-139 {background-color: #FFFF11;}\n",
       ".cython.score-140 {background-color: #FFFF11;}\n",
       ".cython.score-141 {background-color: #FFFF10;}\n",
       ".cython.score-142 {background-color: #FFFF10;}\n",
       ".cython.score-143 {background-color: #FFFF10;}\n",
       ".cython.score-144 {background-color: #FFFF10;}\n",
       ".cython.score-145 {background-color: #FFFF10;}\n",
       ".cython.score-146 {background-color: #FFFF10;}\n",
       ".cython.score-147 {background-color: #FFFF10;}\n",
       ".cython.score-148 {background-color: #FFFF10;}\n",
       ".cython.score-149 {background-color: #FFFF10;}\n",
       ".cython.score-150 {background-color: #FFFF0f;}\n",
       ".cython.score-151 {background-color: #FFFF0f;}\n",
       ".cython.score-152 {background-color: #FFFF0f;}\n",
       ".cython.score-153 {background-color: #FFFF0f;}\n",
       ".cython.score-154 {background-color: #FFFF0f;}\n",
       ".cython.score-155 {background-color: #FFFF0f;}\n",
       ".cython.score-156 {background-color: #FFFF0f;}\n",
       ".cython.score-157 {background-color: #FFFF0f;}\n",
       ".cython.score-158 {background-color: #FFFF0f;}\n",
       ".cython.score-159 {background-color: #FFFF0f;}\n",
       ".cython.score-160 {background-color: #FFFF0f;}\n",
       ".cython.score-161 {background-color: #FFFF0e;}\n",
       ".cython.score-162 {background-color: #FFFF0e;}\n",
       ".cython.score-163 {background-color: #FFFF0e;}\n",
       ".cython.score-164 {background-color: #FFFF0e;}\n",
       ".cython.score-165 {background-color: #FFFF0e;}\n",
       ".cython.score-166 {background-color: #FFFF0e;}\n",
       ".cython.score-167 {background-color: #FFFF0e;}\n",
       ".cython.score-168 {background-color: #FFFF0e;}\n",
       ".cython.score-169 {background-color: #FFFF0e;}\n",
       ".cython.score-170 {background-color: #FFFF0e;}\n",
       ".cython.score-171 {background-color: #FFFF0e;}\n",
       ".cython.score-172 {background-color: #FFFF0e;}\n",
       ".cython.score-173 {background-color: #FFFF0d;}\n",
       ".cython.score-174 {background-color: #FFFF0d;}\n",
       ".cython.score-175 {background-color: #FFFF0d;}\n",
       ".cython.score-176 {background-color: #FFFF0d;}\n",
       ".cython.score-177 {background-color: #FFFF0d;}\n",
       ".cython.score-178 {background-color: #FFFF0d;}\n",
       ".cython.score-179 {background-color: #FFFF0d;}\n",
       ".cython.score-180 {background-color: #FFFF0d;}\n",
       ".cython.score-181 {background-color: #FFFF0d;}\n",
       ".cython.score-182 {background-color: #FFFF0d;}\n",
       ".cython.score-183 {background-color: #FFFF0d;}\n",
       ".cython.score-184 {background-color: #FFFF0d;}\n",
       ".cython.score-185 {background-color: #FFFF0d;}\n",
       ".cython.score-186 {background-color: #FFFF0d;}\n",
       ".cython.score-187 {background-color: #FFFF0c;}\n",
       ".cython.score-188 {background-color: #FFFF0c;}\n",
       ".cython.score-189 {background-color: #FFFF0c;}\n",
       ".cython.score-190 {background-color: #FFFF0c;}\n",
       ".cython.score-191 {background-color: #FFFF0c;}\n",
       ".cython.score-192 {background-color: #FFFF0c;}\n",
       ".cython.score-193 {background-color: #FFFF0c;}\n",
       ".cython.score-194 {background-color: #FFFF0c;}\n",
       ".cython.score-195 {background-color: #FFFF0c;}\n",
       ".cython.score-196 {background-color: #FFFF0c;}\n",
       ".cython.score-197 {background-color: #FFFF0c;}\n",
       ".cython.score-198 {background-color: #FFFF0c;}\n",
       ".cython.score-199 {background-color: #FFFF0c;}\n",
       ".cython.score-200 {background-color: #FFFF0c;}\n",
       ".cython.score-201 {background-color: #FFFF0c;}\n",
       ".cython.score-202 {background-color: #FFFF0c;}\n",
       ".cython.score-203 {background-color: #FFFF0b;}\n",
       ".cython.score-204 {background-color: #FFFF0b;}\n",
       ".cython.score-205 {background-color: #FFFF0b;}\n",
       ".cython.score-206 {background-color: #FFFF0b;}\n",
       ".cython.score-207 {background-color: #FFFF0b;}\n",
       ".cython.score-208 {background-color: #FFFF0b;}\n",
       ".cython.score-209 {background-color: #FFFF0b;}\n",
       ".cython.score-210 {background-color: #FFFF0b;}\n",
       ".cython.score-211 {background-color: #FFFF0b;}\n",
       ".cython.score-212 {background-color: #FFFF0b;}\n",
       ".cython.score-213 {background-color: #FFFF0b;}\n",
       ".cython.score-214 {background-color: #FFFF0b;}\n",
       ".cython.score-215 {background-color: #FFFF0b;}\n",
       ".cython.score-216 {background-color: #FFFF0b;}\n",
       ".cython.score-217 {background-color: #FFFF0b;}\n",
       ".cython.score-218 {background-color: #FFFF0b;}\n",
       ".cython.score-219 {background-color: #FFFF0b;}\n",
       ".cython.score-220 {background-color: #FFFF0b;}\n",
       ".cython.score-221 {background-color: #FFFF0b;}\n",
       ".cython.score-222 {background-color: #FFFF0a;}\n",
       ".cython.score-223 {background-color: #FFFF0a;}\n",
       ".cython.score-224 {background-color: #FFFF0a;}\n",
       ".cython.score-225 {background-color: #FFFF0a;}\n",
       ".cython.score-226 {background-color: #FFFF0a;}\n",
       ".cython.score-227 {background-color: #FFFF0a;}\n",
       ".cython.score-228 {background-color: #FFFF0a;}\n",
       ".cython.score-229 {background-color: #FFFF0a;}\n",
       ".cython.score-230 {background-color: #FFFF0a;}\n",
       ".cython.score-231 {background-color: #FFFF0a;}\n",
       ".cython.score-232 {background-color: #FFFF0a;}\n",
       ".cython.score-233 {background-color: #FFFF0a;}\n",
       ".cython.score-234 {background-color: #FFFF0a;}\n",
       ".cython.score-235 {background-color: #FFFF0a;}\n",
       ".cython.score-236 {background-color: #FFFF0a;}\n",
       ".cython.score-237 {background-color: #FFFF0a;}\n",
       ".cython.score-238 {background-color: #FFFF0a;}\n",
       ".cython.score-239 {background-color: #FFFF0a;}\n",
       ".cython.score-240 {background-color: #FFFF0a;}\n",
       ".cython.score-241 {background-color: #FFFF0a;}\n",
       ".cython.score-242 {background-color: #FFFF0a;}\n",
       ".cython.score-243 {background-color: #FFFF0a;}\n",
       ".cython.score-244 {background-color: #FFFF0a;}\n",
       ".cython.score-245 {background-color: #FFFF0a;}\n",
       ".cython.score-246 {background-color: #FFFF09;}\n",
       ".cython.score-247 {background-color: #FFFF09;}\n",
       ".cython.score-248 {background-color: #FFFF09;}\n",
       ".cython.score-249 {background-color: #FFFF09;}\n",
       ".cython.score-250 {background-color: #FFFF09;}\n",
       ".cython.score-251 {background-color: #FFFF09;}\n",
       ".cython.score-252 {background-color: #FFFF09;}\n",
       ".cython.score-253 {background-color: #FFFF09;}\n",
       ".cython.score-254 {background-color: #FFFF09;}\n",
       ".cython .hll { background-color: #ffffcc }\n",
       ".cython  { background: #f8f8f8; }\n",
       ".cython .c { color: #408080; font-style: italic } /* Comment */\n",
       ".cython .err { border: 1px solid #FF0000 } /* Error */\n",
       ".cython .k { color: #008000; font-weight: bold } /* Keyword */\n",
       ".cython .o { color: #666666 } /* Operator */\n",
       ".cython .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n",
       ".cython .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n",
       ".cython .cp { color: #BC7A00 } /* Comment.Preproc */\n",
       ".cython .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n",
       ".cython .c1 { color: #408080; font-style: italic } /* Comment.Single */\n",
       ".cython .cs { color: #408080; font-style: italic } /* Comment.Special */\n",
       ".cython .gd { color: #A00000 } /* Generic.Deleted */\n",
       ".cython .ge { font-style: italic } /* Generic.Emph */\n",
       ".cython .gr { color: #FF0000 } /* Generic.Error */\n",
       ".cython .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n",
       ".cython .gi { color: #00A000 } /* Generic.Inserted */\n",
       ".cython .go { color: #888888 } /* Generic.Output */\n",
       ".cython .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n",
       ".cython .gs { font-weight: bold } /* Generic.Strong */\n",
       ".cython .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n",
       ".cython .gt { color: #0044DD } /* Generic.Traceback */\n",
       ".cython .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n",
       ".cython .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n",
       ".cython .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n",
       ".cython .kp { color: #008000 } /* Keyword.Pseudo */\n",
       ".cython .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n",
       ".cython .kt { color: #B00040 } /* Keyword.Type */\n",
       ".cython .m { color: #666666 } /* Literal.Number */\n",
       ".cython .s { color: #BA2121 } /* Literal.String */\n",
       ".cython .na { color: #7D9029 } /* Name.Attribute */\n",
       ".cython .nb { color: #008000 } /* Name.Builtin */\n",
       ".cython .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n",
       ".cython .no { color: #880000 } /* Name.Constant */\n",
       ".cython .nd { color: #AA22FF } /* Name.Decorator */\n",
       ".cython .ni { color: #999999; font-weight: bold } /* Name.Entity */\n",
       ".cython .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n",
       ".cython .nf { color: #0000FF } /* Name.Function */\n",
       ".cython .nl { color: #A0A000 } /* Name.Label */\n",
       ".cython .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n",
       ".cython .nt { color: #008000; font-weight: bold } /* Name.Tag */\n",
       ".cython .nv { color: #19177C } /* Name.Variable */\n",
       ".cython .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n",
       ".cython .w { color: #bbbbbb } /* Text.Whitespace */\n",
       ".cython .mb { color: #666666 } /* Literal.Number.Bin */\n",
       ".cython .mf { color: #666666 } /* Literal.Number.Float */\n",
       ".cython .mh { color: #666666 } /* Literal.Number.Hex */\n",
       ".cython .mi { color: #666666 } /* Literal.Number.Integer */\n",
       ".cython .mo { color: #666666 } /* Literal.Number.Oct */\n",
       ".cython .sa { color: #BA2121 } /* Literal.String.Affix */\n",
       ".cython .sb { color: #BA2121 } /* Literal.String.Backtick */\n",
       ".cython .sc { color: #BA2121 } /* Literal.String.Char */\n",
       ".cython .dl { color: #BA2121 } /* Literal.String.Delimiter */\n",
       ".cython .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n",
       ".cython .s2 { color: #BA2121 } /* Literal.String.Double */\n",
       ".cython .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n",
       ".cython .sh { color: #BA2121 } /* Literal.String.Heredoc */\n",
       ".cython .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n",
       ".cython .sx { color: #008000 } /* Literal.String.Other */\n",
       ".cython .sr { color: #BB6688 } /* Literal.String.Regex */\n",
       ".cython .s1 { color: #BA2121 } /* Literal.String.Single */\n",
       ".cython .ss { color: #19177C } /* Literal.String.Symbol */\n",
       ".cython .bp { color: #008000 } /* Name.Builtin.Pseudo */\n",
       ".cython .fm { color: #0000FF } /* Name.Function.Magic */\n",
       ".cython .vc { color: #19177C } /* Name.Variable.Class */\n",
       ".cython .vg { color: #19177C } /* Name.Variable.Global */\n",
       ".cython .vi { color: #19177C } /* Name.Variable.Instance */\n",
       ".cython .vm { color: #19177C } /* Name.Variable.Magic */\n",
       ".cython .il { color: #666666 } /* Literal.Number.Integer.Long */\n",
       "    </style>\n",
       "</head>\n",
       "<body class=\"cython\">\n",
       "<p><span style=\"border-bottom: solid 1px grey;\">Generated by Cython 0.29.20</span></p>\n",
       "<p>\n",
       "    <span style=\"background-color: #FFFF00\">Yellow lines</span> hint at Python interaction.<br />\n",
       "    Click on a line that starts with a \"<code>+</code>\" to see the C code that Cython generated for it.\n",
       "</p>\n",
       "<div class=\"cython\"><pre class=\"cython line score-0\">&#xA0;<span class=\"\">1</span>: <span class=\"k\">from</span> <span class=\"nn\">libc.stdlib</span> <span class=\"k\">cimport</span> <span class=\"n\">rand</span></pre>\n",
       "<pre class=\"cython line score-0\">&#xA0;<span class=\"\">2</span>: <span class=\"k\">cdef</span> <span class=\"kr\">extern</span> <span class=\"k\">from</span> <span class=\"s\">&#39;limits.h&#39;</span><span class=\"p\">:</span></pre>\n",
       "<pre class=\"cython line score-0\">&#xA0;<span class=\"\">3</span>:     <span class=\"nb\">int</span> <span class=\"n\">INT_MAX</span></pre>\n",
       "<pre class=\"cython line score-23\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">4</span>: <span class=\"k\">def</span> <span class=\"nf\">average_cy2</span><span class=\"p\">(</span><span class=\"nb\">int</span> <span class=\"n\">n</span><span class=\"p\">):</span></pre>\n",
       "<pre class='cython code score-23 '>/* Python wrapper */\n",
       "static PyObject *__pyx_pw_46_cython_magic_553e34652a1f7de3ae3551b1aad8ebdd_1average_cy2(PyObject *__pyx_self, PyObject *__pyx_arg_n); /*proto*/\n",
       "static PyMethodDef __pyx_mdef_46_cython_magic_553e34652a1f7de3ae3551b1aad8ebdd_1average_cy2 = {\"average_cy2\", (PyCFunction)__pyx_pw_46_cython_magic_553e34652a1f7de3ae3551b1aad8ebdd_1average_cy2, METH_O, 0};\n",
       "static PyObject *__pyx_pw_46_cython_magic_553e34652a1f7de3ae3551b1aad8ebdd_1average_cy2(PyObject *__pyx_self, PyObject *__pyx_arg_n) {\n",
       "  int __pyx_v_n;\n",
       "  PyObject *__pyx_r = 0;\n",
       "  <span class='refnanny'>__Pyx_RefNannyDeclarations</span>\n",
       "  <span class='refnanny'>__Pyx_RefNannySetupContext</span>(\"average_cy2 (wrapper)\", 0);\n",
       "  assert(__pyx_arg_n); {\n",
       "    __pyx_v_n = <span class='pyx_c_api'>__Pyx_PyInt_As_int</span>(__pyx_arg_n); if (unlikely((__pyx_v_n == (int)-1) &amp;&amp; <span class='py_c_api'>PyErr_Occurred</span>())) <span class='error_goto'>__PYX_ERR(0, 4, __pyx_L3_error)</span>\n",
       "  }\n",
       "  goto __pyx_L4_argument_unpacking_done;\n",
       "  __pyx_L3_error:;\n",
       "  <span class='pyx_c_api'>__Pyx_AddTraceback</span>(\"_cython_magic_553e34652a1f7de3ae3551b1aad8ebdd.average_cy2\", __pyx_clineno, __pyx_lineno, __pyx_filename);\n",
       "  <span class='refnanny'>__Pyx_RefNannyFinishContext</span>();\n",
       "  return NULL;\n",
       "  __pyx_L4_argument_unpacking_done:;\n",
       "  __pyx_r = __pyx_pf_46_cython_magic_553e34652a1f7de3ae3551b1aad8ebdd_average_cy2(__pyx_self, ((int)__pyx_v_n));\n",
       "  int __pyx_lineno = 0;\n",
       "  const char *__pyx_filename = NULL;\n",
       "  int __pyx_clineno = 0;\n",
       "\n",
       "  /* function exit code */\n",
       "  <span class='refnanny'>__Pyx_RefNannyFinishContext</span>();\n",
       "  return __pyx_r;\n",
       "}\n",
       "\n",
       "static PyObject *__pyx_pf_46_cython_magic_553e34652a1f7de3ae3551b1aad8ebdd_average_cy2(CYTHON_UNUSED PyObject *__pyx_self, int __pyx_v_n) {\n",
       "  CYTHON_UNUSED int __pyx_v_i;\n",
       "  float __pyx_v_s;\n",
       "  PyObject *__pyx_r = NULL;\n",
       "  <span class='refnanny'>__Pyx_RefNannyDeclarations</span>\n",
       "  <span class='refnanny'>__Pyx_RefNannySetupContext</span>(\"average_cy2\", 0);\n",
       "/* … */\n",
       "  /* function exit code */\n",
       "  __pyx_L1_error:;\n",
       "  <span class='pyx_macro_api'>__Pyx_XDECREF</span>(__pyx_t_5);\n",
       "  <span class='pyx_c_api'>__Pyx_AddTraceback</span>(\"_cython_magic_553e34652a1f7de3ae3551b1aad8ebdd.average_cy2\", __pyx_clineno, __pyx_lineno, __pyx_filename);\n",
       "  __pyx_r = NULL;\n",
       "  __pyx_L0:;\n",
       "  <span class='refnanny'>__Pyx_XGIVEREF</span>(__pyx_r);\n",
       "  <span class='refnanny'>__Pyx_RefNannyFinishContext</span>();\n",
       "  return __pyx_r;\n",
       "}\n",
       "/* … */\n",
       "  __pyx_tuple_ = <span class='py_c_api'>PyTuple_Pack</span>(4, __pyx_n_s_n, __pyx_n_s_n, __pyx_n_s_i, __pyx_n_s_s);<span class='error_goto'> if (unlikely(!__pyx_tuple_)) __PYX_ERR(0, 4, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_tuple_);\n",
       "  <span class='refnanny'>__Pyx_GIVEREF</span>(__pyx_tuple_);\n",
       "/* … */\n",
       "  __pyx_t_1 = PyCFunction_NewEx(&amp;__pyx_mdef_46_cython_magic_553e34652a1f7de3ae3551b1aad8ebdd_1average_cy2, NULL, __pyx_n_s_cython_magic_553e34652a1f7de3ae);<span class='error_goto'> if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_1);\n",
       "  if (<span class='py_c_api'>PyDict_SetItem</span>(__pyx_d, __pyx_n_s_average_cy2, __pyx_t_1) &lt; 0) <span class='error_goto'>__PYX_ERR(0, 4, __pyx_L1_error)</span>\n",
       "  <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_1); __pyx_t_1 = 0;\n",
       "</pre><pre class=\"cython line score-0\">&#xA0;<span class=\"\">5</span>:     <span class=\"k\">cdef</span> <span class=\"kt\">int</span> <span class=\"nf\">i</span></pre>\n",
       "<pre class=\"cython line score-0\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">6</span>:     <span class=\"k\">cdef</span> <span class=\"kt\">float</span> <span class=\"nf\">s</span> <span class=\"o\">=</span> <span class=\"mf\">0</span></pre>\n",
       "<pre class='cython code score-0 '>  __pyx_v_s = 0.0;\n",
       "</pre><pre class=\"cython line score-0\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">7</span>:     <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">n</span><span class=\"p\">):</span></pre>\n",
       "<pre class='cython code score-0 '>  __pyx_t_1 = __pyx_v_n;\n",
       "  __pyx_t_2 = __pyx_t_1;\n",
       "  for (__pyx_t_3 = 0; __pyx_t_3 &lt; __pyx_t_2; __pyx_t_3+=1) {\n",
       "    __pyx_v_i = __pyx_t_3;\n",
       "</pre><pre class=\"cython line score-5\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">8</span>:         <span class=\"n\">s</span> <span class=\"o\">+=</span> <span class=\"n\">rand</span><span class=\"p\">()</span> <span class=\"o\">/</span> <span class=\"n\">INT_MAX</span></pre>\n",
       "<pre class='cython code score-5 '>    __pyx_t_4 = rand();\n",
       "    if (unlikely(INT_MAX == 0)) {\n",
       "      <span class='py_c_api'>PyErr_SetString</span>(PyExc_ZeroDivisionError, \"float division\");\n",
       "      <span class='error_goto'>__PYX_ERR(0, 8, __pyx_L1_error)</span>\n",
       "    }\n",
       "    __pyx_v_s = (__pyx_v_s + (((double)__pyx_t_4) / ((double)INT_MAX)));\n",
       "  }\n",
       "</pre><pre class=\"cython line score-11\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">9</span>:     <span class=\"k\">return</span> <span class=\"n\">s</span> <span class=\"o\">/</span> <span class=\"n\">n</span></pre>\n",
       "<pre class='cython code score-11 '>  <span class='pyx_macro_api'>__Pyx_XDECREF</span>(__pyx_r);\n",
       "  if (unlikely(__pyx_v_n == 0)) {\n",
       "    <span class='py_c_api'>PyErr_SetString</span>(PyExc_ZeroDivisionError, \"float division\");\n",
       "    <span class='error_goto'>__PYX_ERR(0, 9, __pyx_L1_error)</span>\n",
       "  }\n",
       "  __pyx_t_5 = <span class='py_c_api'>PyFloat_FromDouble</span>((__pyx_v_s / ((float)__pyx_v_n)));<span class='error_goto'> if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 9, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_5);\n",
       "  __pyx_r = __pyx_t_5;\n",
       "  __pyx_t_5 = 0;\n",
       "  goto __pyx_L0;\n",
       "</pre></div></body></html>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%%cython -a\n",
    "from libc.stdlib cimport rand  \n",
    "cdef extern from 'limits.h':  \n",
    "    int INT_MAX  \n",
    "def average_cy2(int n):\n",
    "    cdef int i\n",
    "    cdef float s = 0\n",
    "    for i in range(n):\n",
    "        s += rand() / INT_MAX  \n",
    "    return s / n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 62 ms, sys: 348 µs, total: 62.3 ms\n",
      "Wall time: 62.3 ms\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "0.500017523765564"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time average_cy2(n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "61.4 ms ± 1.75 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n"
     ]
    }
   ],
   "source": [
    "%timeit average_cy2(n)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Prime Numbers"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Pure Python"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [],
   "source": [
    "def is_prime(I):\n",
    "    if I % 2 == 0: return False  \n",
    "    for i in range(3, int(I ** 0.5) + 1, 2):  \n",
    "        if I % i == 0: return False  \n",
    "    return True  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "100000003"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "n = int(1e8 + 3)  \n",
    "n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 25 µs, sys: 0 ns, total: 25 µs\n",
      "Wall time: 26.9 µs\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time is_prime(n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "100000007"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "p1 = int(1e8 + 7)  \n",
    "p1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 418 µs, sys: 0 ns, total: 418 µs\n",
      "Wall time: 422 µs\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time is_prime(p1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [],
   "source": [
    "p2 = 100109100129162907  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "57"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "p2.bit_length()  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 16.6 s, sys: 49.2 ms, total: 16.6 s\n",
      "Wall time: 16.7 s\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 32,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time is_prime(p2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Numba"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "metadata": {},
   "outputs": [],
   "source": [
    "is_prime_nb = numba.jit(is_prime)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 102 ms, sys: 3.24 ms, total: 106 ms\n",
      "Wall time: 107 ms\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time is_prime_nb(n)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 6 µs, sys: 1e+03 ns, total: 7 µs\n",
      "Wall time: 8.82 µs\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time is_prime_nb(n)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 27 µs, sys: 1e+03 ns, total: 28 µs\n",
      "Wall time: 29.3 µs\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time is_prime_nb(p1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 1.5 s, sys: 7.28 ms, total: 1.51 s\n",
      "Wall time: 1.51 s\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 37,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time is_prime_nb(p2)  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Cython"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%cython\n",
    "def is_prime_cy1(I):\n",
    "    if I % 2 == 0: return False\n",
    "    for i in range(3, int(I ** 0.5) + 1, 2):\n",
    "        if I % i == 0: return False\n",
    "    return True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "332 µs ± 8.44 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n"
     ]
    }
   ],
   "source": [
    "%timeit is_prime(p1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "183 µs ± 449 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n"
     ]
    }
   ],
   "source": [
    "%timeit is_prime_cy1(p1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%cython\n",
    "def is_prime_cy2(long I):  \n",
    "    cdef long i  \n",
    "    if I % 2 == 0: return False\n",
    "    for i in range(3, int(I ** 0.5) + 1, 2):\n",
    "        if I % i == 0: return False\n",
    "    return True"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "42.9 µs ± 154 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n"
     ]
    }
   ],
   "source": [
    "%timeit is_prime_cy2(p1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 1.47 s, sys: 5.69 ms, total: 1.48 s\n",
      "Wall time: 1.47 s\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time is_prime_nb(p2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 1.37 s, sys: 4.4 ms, total: 1.38 s\n",
      "Wall time: 1.37 s\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 44,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time is_prime_cy2(p2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Multiprocessing"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [],
   "source": [
    "import multiprocessing as mp"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [],
   "source": [
    "pool = mp.Pool(processes=4)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 1.12 ms, sys: 1.69 ms, total: 2.81 ms\n",
      "Wall time: 3.6 ms\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[True, True, True, True, True, True, True, True, True, True]"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time pool.map(is_prime, 10 * [p1])  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 6.42 ms, sys: 2.84 ms, total: 9.26 ms\n",
      "Wall time: 4.95 s\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[True, True, True, True, True, True, True, True, True, True]"
      ]
     },
     "execution_count": 48,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time pool.map(is_prime_nb, 10 * [p2])  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 3.3 ms, sys: 2.03 ms, total: 5.33 ms\n",
      "Wall time: 4.46 s\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[True, True, True, True, True, True, True, True, True, True]"
      ]
     },
     "execution_count": 49,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time pool.map(is_prime_cy2, 10 * [p2])  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Fibonacci Numbers"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Recursive Algorithm"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [],
   "source": [
    "from numba import njit"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "metadata": {},
   "outputs": [],
   "source": [
    "def fib_rec_py1(n):\n",
    "    if n < 2:\n",
    "        return n\n",
    "    else:\n",
    "        return fib_rec_py1(n - 1) + fib_rec_py1(n - 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 3.38 s, sys: 9.13 ms, total: 3.39 s\n",
      "Wall time: 3.39 s\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "9227465"
      ]
     },
     "execution_count": 52,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time fib_rec_py1(35)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [],
   "source": [
    "@njit\n",
    "def fib_rec_nb(n):\n",
    "    if n < 2:\n",
    "        return n\n",
    "    else:\n",
    "        return fib_rec_nb(n - 1) + fib_rec_nb(n - 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 155 ms, sys: 9.59 ms, total: 165 ms\n",
      "Wall time: 164 ms\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "9227465"
      ]
     },
     "execution_count": 54,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time fib_rec_nb(35)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 90.7 ms, sys: 393 µs, total: 91.1 ms\n",
      "Wall time: 91 ms\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "9227465"
      ]
     },
     "execution_count": 55,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time fib_rec_nb(35)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%cython\n",
    "def fib_rec_cy(int n):\n",
    "    if n < 2:\n",
    "        return n\n",
    "    else:\n",
    "        return fib_rec_cy(n - 1) + fib_rec_cy(n - 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 656 ms, sys: 2.37 ms, total: 659 ms\n",
      "Wall time: 656 ms\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "9227465"
      ]
     },
     "execution_count": 57,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time fib_rec_cy(35)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "metadata": {},
   "outputs": [],
   "source": [
    "from functools import lru_cache as cache"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "metadata": {},
   "outputs": [],
   "source": [
    "@cache(maxsize=None)  \n",
    "def fib_rec_py2(n):\n",
    "    if n < 2:\n",
    "        return n\n",
    "    else:\n",
    "        return fib_rec_py2(n - 1) + fib_rec_py2(n - 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 22 µs, sys: 0 ns, total: 22 µs\n",
      "Wall time: 26 µs\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "9227465"
      ]
     },
     "execution_count": 60,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time fib_rec_py2(35)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 23 µs, sys: 0 ns, total: 23 µs\n",
      "Wall time: 25.7 µs\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "23416728348467685"
      ]
     },
     "execution_count": 61,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time fib_rec_py2(80)  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Iterative Algorithm "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "metadata": {},
   "outputs": [],
   "source": [
    "def fib_it_py(n):\n",
    "    x, y = 0, 1\n",
    "    for i in range(1, n + 1):\n",
    "        x, y = y, x + y\n",
    "    return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 8 µs, sys: 1 µs, total: 9 µs\n",
      "Wall time: 11 µs\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "23416728348467685"
      ]
     },
     "execution_count": 63,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time fib_it_py(80)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "metadata": {},
   "outputs": [],
   "source": [
    "fib_it_nb = numba.jit(fib_it_py)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 68.7 ms, sys: 3.43 ms, total: 72.2 ms\n",
      "Wall time: 71.2 ms\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "23416728348467685"
      ]
     },
     "execution_count": 65,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time fib_it_nb(80)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 5 µs, sys: 1 µs, total: 6 µs\n",
      "Wall time: 7.87 µs\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "23416728348467685"
      ]
     },
     "execution_count": 66,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time fib_it_nb(80)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%cython\n",
    "def fib_it_cy1(int n):\n",
    "    cdef long i\n",
    "    cdef long x = 0, y = 1\n",
    "    for i in range(1, n + 1):\n",
    "        x, y = y, x + y\n",
    "    return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 2 µs, sys: 0 ns, total: 2 µs\n",
      "Wall time: 5.01 µs\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "23416728348467685"
      ]
     },
     "execution_count": 68,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time fib_it_cy1(80)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "9969216677189303386214405760200\n",
      "CPU times: user 177 µs, sys: 135 µs, total: 312 µs\n",
      "Wall time: 209 µs\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "fn = fib_rec_py2(150)  \n",
    "print(fn)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "103"
      ]
     },
     "execution_count": 70,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fn.bit_length()  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "6792540214324356296\n",
      "CPU times: user 123 µs, sys: 51 µs, total: 174 µs\n",
      "Wall time: 141 µs\n"
     ]
    }
   ],
   "source": [
    "%%time \n",
    "fn = fib_it_nb(150)  \n",
    "print(fn)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "63"
      ]
     },
     "execution_count": 72,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fn.bit_length()  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "6792540214324356296\n",
      "CPU times: user 133 µs, sys: 56 µs, total: 189 µs\n",
      "Wall time: 175 µs\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "fn = fib_it_cy1(150)  \n",
    "print(fn)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "63"
      ]
     },
     "execution_count": 74,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fn.bit_length()  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%cython\n",
    "cdef extern from *:\n",
    "    ctypedef int int128 '__int128_t'  \n",
    "def fib_it_cy2(int n):\n",
    "    cdef int128 i  \n",
    "    cdef int128 x = 0, y = 1  \n",
    "    for i in range(1, n + 1):\n",
    "        x, y = y, x + y\n",
    "    return x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "9969216677189303386214405760200\n",
      "CPU times: user 154 µs, sys: 87 µs, total: 241 µs\n",
      "Wall time: 192 µs\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "fn = fib_it_cy2(150)  \n",
    "print(fn)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "103"
      ]
     },
     "execution_count": 77,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "fn.bit_length()  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## The Number Pi"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The code example is taken from [StackExchange](https://codereview.stackexchange.com/questions/69370/monte-carlo-pi-calculation)."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "metadata": {},
   "outputs": [],
   "source": [
    "import random\n",
    "import numpy as np\n",
    "from pylab import mpl, plt\n",
    "plt.style.use('seaborn')\n",
    "mpl.rcParams['font.family'] = 'serif'\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "metadata": {},
   "outputs": [],
   "source": [
    "rn = [(random.random() * 2 - 1, random.random() * 2 - 1)\n",
    "      for _ in range(500)]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[-0.65353112, -0.10654507],\n",
       "       [-0.37339957,  0.94181444],\n",
       "       [-0.06304137,  0.79649017],\n",
       "       [ 0.13088067,  0.93271846],\n",
       "       [-0.53271331,  0.62477924]])"
      ]
     },
     "execution_count": 80,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rn = np.array(rn)\n",
    "rn[:5]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(-1.1, 1.1)"
      ]
     },
     "execution_count": 81,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 504x504 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "fig = plt.figure(figsize=(7, 7))\n",
    "ax = fig.add_subplot(1, 1, 1)\n",
    "circ = plt.Circle((0, 0), radius=1, edgecolor='g', lw=2.0,\n",
    "                  facecolor='None')  \n",
    "box = plt.Rectangle((-1, -1), 2, 2, edgecolor='b', alpha=0.3)  \n",
    "ax.add_patch(circ)  \n",
    "ax.add_patch(box)  \n",
    "plt.plot(rn[:, 0], rn[:, 1], 'r.')  \n",
    "plt.ylim(-1.1, 1.1)\n",
    "plt.xlim(-1.1, 1.1)\n",
    "# plt.savefig('../../images/ch10/perf_01.png');"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "metadata": {},
   "outputs": [],
   "source": [
    "n = int(1e7)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 213 ms, sys: 34.4 ms, total: 247 ms\n",
      "Wall time: 247 ms\n"
     ]
    }
   ],
   "source": [
    "%time rn = np.random.random((n, 2)) * 2 - 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "160000000"
      ]
     },
     "execution_count": 84,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "rn.nbytes"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 247 ms, sys: 87 ms, total: 334 ms\n",
      "Wall time: 334 ms\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([0.548, 0.761, 0.104, 0.384, 1.144, 0.706, 0.769, 0.592])"
      ]
     },
     "execution_count": 85,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time distance = np.sqrt((rn ** 2).sum(axis=1))  \n",
    "distance[:8].round(3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 29.6 ms, sys: 5.38 ms, total: 34.9 ms\n",
      "Wall time: 32.7 ms\n"
     ]
    }
   ],
   "source": [
    "%time frac = (distance <= 1.0).sum() / len(distance)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3.1422072"
      ]
     },
     "execution_count": 87,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pi_mcs = frac * 4  \n",
    "pi_mcs  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 88,
   "metadata": {},
   "outputs": [],
   "source": [
    "def mcs_pi_py(n):\n",
    "    circle = 0\n",
    "    for _ in range(n):\n",
    "        x, y = random.random(), random.random()\n",
    "        if (x ** 2 + y ** 2) ** 0.5 <= 1:\n",
    "            circle += 1\n",
    "    return (4 * circle) / n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 4.83 s, sys: 24.5 ms, total: 4.86 s\n",
      "Wall time: 4.88 s\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "3.1409772"
      ]
     },
     "execution_count": 89,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time mcs_pi_py(n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 90,
   "metadata": {},
   "outputs": [],
   "source": [
    "mcs_pi_nb = numba.jit(mcs_pi_py)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 91,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 317 ms, sys: 6.23 ms, total: 324 ms\n",
      "Wall time: 324 ms\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "3.140912"
      ]
     },
     "execution_count": 91,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time mcs_pi_nb(n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 92,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 119 ms, sys: 943 µs, total: 120 ms\n",
      "Wall time: 120 ms\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "3.140324"
      ]
     },
     "execution_count": 92,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time mcs_pi_nb(n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 93,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<!DOCTYPE html>\n",
       "<!-- Generated by Cython 0.29.20 -->\n",
       "<html>\n",
       "<head>\n",
       "    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n",
       "    <title>Cython: _cython_magic_f06e2f6732b65e46645f28671e6aca06.pyx</title>\n",
       "    <style type=\"text/css\">\n",
       "    \n",
       "body.cython { font-family: courier; font-size: 12; }\n",
       "\n",
       ".cython.tag  {  }\n",
       ".cython.line { margin: 0em }\n",
       ".cython.code { font-size: 9; color: #444444; display: none; margin: 0px 0px 0px 8px; border-left: 8px none; }\n",
       "\n",
       ".cython.line .run { background-color: #B0FFB0; }\n",
       ".cython.line .mis { background-color: #FFB0B0; }\n",
       ".cython.code.run  { border-left: 8px solid #B0FFB0; }\n",
       ".cython.code.mis  { border-left: 8px solid #FFB0B0; }\n",
       "\n",
       ".cython.code .py_c_api  { color: red; }\n",
       ".cython.code .py_macro_api  { color: #FF7000; }\n",
       ".cython.code .pyx_c_api  { color: #FF3000; }\n",
       ".cython.code .pyx_macro_api  { color: #FF7000; }\n",
       ".cython.code .refnanny  { color: #FFA000; }\n",
       ".cython.code .trace  { color: #FFA000; }\n",
       ".cython.code .error_goto  { color: #FFA000; }\n",
       "\n",
       ".cython.code .coerce  { color: #008000; border: 1px dotted #008000 }\n",
       ".cython.code .py_attr { color: #FF0000; font-weight: bold; }\n",
       ".cython.code .c_attr  { color: #0000FF; }\n",
       ".cython.code .py_call { color: #FF0000; font-weight: bold; }\n",
       ".cython.code .c_call  { color: #0000FF; }\n",
       "\n",
       ".cython.score-0 {background-color: #FFFFff;}\n",
       ".cython.score-1 {background-color: #FFFFe7;}\n",
       ".cython.score-2 {background-color: #FFFFd4;}\n",
       ".cython.score-3 {background-color: #FFFFc4;}\n",
       ".cython.score-4 {background-color: #FFFFb6;}\n",
       ".cython.score-5 {background-color: #FFFFaa;}\n",
       ".cython.score-6 {background-color: #FFFF9f;}\n",
       ".cython.score-7 {background-color: #FFFF96;}\n",
       ".cython.score-8 {background-color: #FFFF8d;}\n",
       ".cython.score-9 {background-color: #FFFF86;}\n",
       ".cython.score-10 {background-color: #FFFF7f;}\n",
       ".cython.score-11 {background-color: #FFFF79;}\n",
       ".cython.score-12 {background-color: #FFFF73;}\n",
       ".cython.score-13 {background-color: #FFFF6e;}\n",
       ".cython.score-14 {background-color: #FFFF6a;}\n",
       ".cython.score-15 {background-color: #FFFF66;}\n",
       ".cython.score-16 {background-color: #FFFF62;}\n",
       ".cython.score-17 {background-color: #FFFF5e;}\n",
       ".cython.score-18 {background-color: #FFFF5b;}\n",
       ".cython.score-19 {background-color: #FFFF57;}\n",
       ".cython.score-20 {background-color: #FFFF55;}\n",
       ".cython.score-21 {background-color: #FFFF52;}\n",
       ".cython.score-22 {background-color: #FFFF4f;}\n",
       ".cython.score-23 {background-color: #FFFF4d;}\n",
       ".cython.score-24 {background-color: #FFFF4b;}\n",
       ".cython.score-25 {background-color: #FFFF48;}\n",
       ".cython.score-26 {background-color: #FFFF46;}\n",
       ".cython.score-27 {background-color: #FFFF44;}\n",
       ".cython.score-28 {background-color: #FFFF43;}\n",
       ".cython.score-29 {background-color: #FFFF41;}\n",
       ".cython.score-30 {background-color: #FFFF3f;}\n",
       ".cython.score-31 {background-color: #FFFF3e;}\n",
       ".cython.score-32 {background-color: #FFFF3c;}\n",
       ".cython.score-33 {background-color: #FFFF3b;}\n",
       ".cython.score-34 {background-color: #FFFF39;}\n",
       ".cython.score-35 {background-color: #FFFF38;}\n",
       ".cython.score-36 {background-color: #FFFF37;}\n",
       ".cython.score-37 {background-color: #FFFF36;}\n",
       ".cython.score-38 {background-color: #FFFF35;}\n",
       ".cython.score-39 {background-color: #FFFF34;}\n",
       ".cython.score-40 {background-color: #FFFF33;}\n",
       ".cython.score-41 {background-color: #FFFF32;}\n",
       ".cython.score-42 {background-color: #FFFF31;}\n",
       ".cython.score-43 {background-color: #FFFF30;}\n",
       ".cython.score-44 {background-color: #FFFF2f;}\n",
       ".cython.score-45 {background-color: #FFFF2e;}\n",
       ".cython.score-46 {background-color: #FFFF2d;}\n",
       ".cython.score-47 {background-color: #FFFF2c;}\n",
       ".cython.score-48 {background-color: #FFFF2b;}\n",
       ".cython.score-49 {background-color: #FFFF2b;}\n",
       ".cython.score-50 {background-color: #FFFF2a;}\n",
       ".cython.score-51 {background-color: #FFFF29;}\n",
       ".cython.score-52 {background-color: #FFFF29;}\n",
       ".cython.score-53 {background-color: #FFFF28;}\n",
       ".cython.score-54 {background-color: #FFFF27;}\n",
       ".cython.score-55 {background-color: #FFFF27;}\n",
       ".cython.score-56 {background-color: #FFFF26;}\n",
       ".cython.score-57 {background-color: #FFFF26;}\n",
       ".cython.score-58 {background-color: #FFFF25;}\n",
       ".cython.score-59 {background-color: #FFFF24;}\n",
       ".cython.score-60 {background-color: #FFFF24;}\n",
       ".cython.score-61 {background-color: #FFFF23;}\n",
       ".cython.score-62 {background-color: #FFFF23;}\n",
       ".cython.score-63 {background-color: #FFFF22;}\n",
       ".cython.score-64 {background-color: #FFFF22;}\n",
       ".cython.score-65 {background-color: #FFFF22;}\n",
       ".cython.score-66 {background-color: #FFFF21;}\n",
       ".cython.score-67 {background-color: #FFFF21;}\n",
       ".cython.score-68 {background-color: #FFFF20;}\n",
       ".cython.score-69 {background-color: #FFFF20;}\n",
       ".cython.score-70 {background-color: #FFFF1f;}\n",
       ".cython.score-71 {background-color: #FFFF1f;}\n",
       ".cython.score-72 {background-color: #FFFF1f;}\n",
       ".cython.score-73 {background-color: #FFFF1e;}\n",
       ".cython.score-74 {background-color: #FFFF1e;}\n",
       ".cython.score-75 {background-color: #FFFF1e;}\n",
       ".cython.score-76 {background-color: #FFFF1d;}\n",
       ".cython.score-77 {background-color: #FFFF1d;}\n",
       ".cython.score-78 {background-color: #FFFF1c;}\n",
       ".cython.score-79 {background-color: #FFFF1c;}\n",
       ".cython.score-80 {background-color: #FFFF1c;}\n",
       ".cython.score-81 {background-color: #FFFF1c;}\n",
       ".cython.score-82 {background-color: #FFFF1b;}\n",
       ".cython.score-83 {background-color: #FFFF1b;}\n",
       ".cython.score-84 {background-color: #FFFF1b;}\n",
       ".cython.score-85 {background-color: #FFFF1a;}\n",
       ".cython.score-86 {background-color: #FFFF1a;}\n",
       ".cython.score-87 {background-color: #FFFF1a;}\n",
       ".cython.score-88 {background-color: #FFFF1a;}\n",
       ".cython.score-89 {background-color: #FFFF19;}\n",
       ".cython.score-90 {background-color: #FFFF19;}\n",
       ".cython.score-91 {background-color: #FFFF19;}\n",
       ".cython.score-92 {background-color: #FFFF19;}\n",
       ".cython.score-93 {background-color: #FFFF18;}\n",
       ".cython.score-94 {background-color: #FFFF18;}\n",
       ".cython.score-95 {background-color: #FFFF18;}\n",
       ".cython.score-96 {background-color: #FFFF18;}\n",
       ".cython.score-97 {background-color: #FFFF17;}\n",
       ".cython.score-98 {background-color: #FFFF17;}\n",
       ".cython.score-99 {background-color: #FFFF17;}\n",
       ".cython.score-100 {background-color: #FFFF17;}\n",
       ".cython.score-101 {background-color: #FFFF16;}\n",
       ".cython.score-102 {background-color: #FFFF16;}\n",
       ".cython.score-103 {background-color: #FFFF16;}\n",
       ".cython.score-104 {background-color: #FFFF16;}\n",
       ".cython.score-105 {background-color: #FFFF16;}\n",
       ".cython.score-106 {background-color: #FFFF15;}\n",
       ".cython.score-107 {background-color: #FFFF15;}\n",
       ".cython.score-108 {background-color: #FFFF15;}\n",
       ".cython.score-109 {background-color: #FFFF15;}\n",
       ".cython.score-110 {background-color: #FFFF15;}\n",
       ".cython.score-111 {background-color: #FFFF15;}\n",
       ".cython.score-112 {background-color: #FFFF14;}\n",
       ".cython.score-113 {background-color: #FFFF14;}\n",
       ".cython.score-114 {background-color: #FFFF14;}\n",
       ".cython.score-115 {background-color: #FFFF14;}\n",
       ".cython.score-116 {background-color: #FFFF14;}\n",
       ".cython.score-117 {background-color: #FFFF14;}\n",
       ".cython.score-118 {background-color: #FFFF13;}\n",
       ".cython.score-119 {background-color: #FFFF13;}\n",
       ".cython.score-120 {background-color: #FFFF13;}\n",
       ".cython.score-121 {background-color: #FFFF13;}\n",
       ".cython.score-122 {background-color: #FFFF13;}\n",
       ".cython.score-123 {background-color: #FFFF13;}\n",
       ".cython.score-124 {background-color: #FFFF13;}\n",
       ".cython.score-125 {background-color: #FFFF12;}\n",
       ".cython.score-126 {background-color: #FFFF12;}\n",
       ".cython.score-127 {background-color: #FFFF12;}\n",
       ".cython.score-128 {background-color: #FFFF12;}\n",
       ".cython.score-129 {background-color: #FFFF12;}\n",
       ".cython.score-130 {background-color: #FFFF12;}\n",
       ".cython.score-131 {background-color: #FFFF12;}\n",
       ".cython.score-132 {background-color: #FFFF11;}\n",
       ".cython.score-133 {background-color: #FFFF11;}\n",
       ".cython.score-134 {background-color: #FFFF11;}\n",
       ".cython.score-135 {background-color: #FFFF11;}\n",
       ".cython.score-136 {background-color: #FFFF11;}\n",
       ".cython.score-137 {background-color: #FFFF11;}\n",
       ".cython.score-138 {background-color: #FFFF11;}\n",
       ".cython.score-139 {background-color: #FFFF11;}\n",
       ".cython.score-140 {background-color: #FFFF11;}\n",
       ".cython.score-141 {background-color: #FFFF10;}\n",
       ".cython.score-142 {background-color: #FFFF10;}\n",
       ".cython.score-143 {background-color: #FFFF10;}\n",
       ".cython.score-144 {background-color: #FFFF10;}\n",
       ".cython.score-145 {background-color: #FFFF10;}\n",
       ".cython.score-146 {background-color: #FFFF10;}\n",
       ".cython.score-147 {background-color: #FFFF10;}\n",
       ".cython.score-148 {background-color: #FFFF10;}\n",
       ".cython.score-149 {background-color: #FFFF10;}\n",
       ".cython.score-150 {background-color: #FFFF0f;}\n",
       ".cython.score-151 {background-color: #FFFF0f;}\n",
       ".cython.score-152 {background-color: #FFFF0f;}\n",
       ".cython.score-153 {background-color: #FFFF0f;}\n",
       ".cython.score-154 {background-color: #FFFF0f;}\n",
       ".cython.score-155 {background-color: #FFFF0f;}\n",
       ".cython.score-156 {background-color: #FFFF0f;}\n",
       ".cython.score-157 {background-color: #FFFF0f;}\n",
       ".cython.score-158 {background-color: #FFFF0f;}\n",
       ".cython.score-159 {background-color: #FFFF0f;}\n",
       ".cython.score-160 {background-color: #FFFF0f;}\n",
       ".cython.score-161 {background-color: #FFFF0e;}\n",
       ".cython.score-162 {background-color: #FFFF0e;}\n",
       ".cython.score-163 {background-color: #FFFF0e;}\n",
       ".cython.score-164 {background-color: #FFFF0e;}\n",
       ".cython.score-165 {background-color: #FFFF0e;}\n",
       ".cython.score-166 {background-color: #FFFF0e;}\n",
       ".cython.score-167 {background-color: #FFFF0e;}\n",
       ".cython.score-168 {background-color: #FFFF0e;}\n",
       ".cython.score-169 {background-color: #FFFF0e;}\n",
       ".cython.score-170 {background-color: #FFFF0e;}\n",
       ".cython.score-171 {background-color: #FFFF0e;}\n",
       ".cython.score-172 {background-color: #FFFF0e;}\n",
       ".cython.score-173 {background-color: #FFFF0d;}\n",
       ".cython.score-174 {background-color: #FFFF0d;}\n",
       ".cython.score-175 {background-color: #FFFF0d;}\n",
       ".cython.score-176 {background-color: #FFFF0d;}\n",
       ".cython.score-177 {background-color: #FFFF0d;}\n",
       ".cython.score-178 {background-color: #FFFF0d;}\n",
       ".cython.score-179 {background-color: #FFFF0d;}\n",
       ".cython.score-180 {background-color: #FFFF0d;}\n",
       ".cython.score-181 {background-color: #FFFF0d;}\n",
       ".cython.score-182 {background-color: #FFFF0d;}\n",
       ".cython.score-183 {background-color: #FFFF0d;}\n",
       ".cython.score-184 {background-color: #FFFF0d;}\n",
       ".cython.score-185 {background-color: #FFFF0d;}\n",
       ".cython.score-186 {background-color: #FFFF0d;}\n",
       ".cython.score-187 {background-color: #FFFF0c;}\n",
       ".cython.score-188 {background-color: #FFFF0c;}\n",
       ".cython.score-189 {background-color: #FFFF0c;}\n",
       ".cython.score-190 {background-color: #FFFF0c;}\n",
       ".cython.score-191 {background-color: #FFFF0c;}\n",
       ".cython.score-192 {background-color: #FFFF0c;}\n",
       ".cython.score-193 {background-color: #FFFF0c;}\n",
       ".cython.score-194 {background-color: #FFFF0c;}\n",
       ".cython.score-195 {background-color: #FFFF0c;}\n",
       ".cython.score-196 {background-color: #FFFF0c;}\n",
       ".cython.score-197 {background-color: #FFFF0c;}\n",
       ".cython.score-198 {background-color: #FFFF0c;}\n",
       ".cython.score-199 {background-color: #FFFF0c;}\n",
       ".cython.score-200 {background-color: #FFFF0c;}\n",
       ".cython.score-201 {background-color: #FFFF0c;}\n",
       ".cython.score-202 {background-color: #FFFF0c;}\n",
       ".cython.score-203 {background-color: #FFFF0b;}\n",
       ".cython.score-204 {background-color: #FFFF0b;}\n",
       ".cython.score-205 {background-color: #FFFF0b;}\n",
       ".cython.score-206 {background-color: #FFFF0b;}\n",
       ".cython.score-207 {background-color: #FFFF0b;}\n",
       ".cython.score-208 {background-color: #FFFF0b;}\n",
       ".cython.score-209 {background-color: #FFFF0b;}\n",
       ".cython.score-210 {background-color: #FFFF0b;}\n",
       ".cython.score-211 {background-color: #FFFF0b;}\n",
       ".cython.score-212 {background-color: #FFFF0b;}\n",
       ".cython.score-213 {background-color: #FFFF0b;}\n",
       ".cython.score-214 {background-color: #FFFF0b;}\n",
       ".cython.score-215 {background-color: #FFFF0b;}\n",
       ".cython.score-216 {background-color: #FFFF0b;}\n",
       ".cython.score-217 {background-color: #FFFF0b;}\n",
       ".cython.score-218 {background-color: #FFFF0b;}\n",
       ".cython.score-219 {background-color: #FFFF0b;}\n",
       ".cython.score-220 {background-color: #FFFF0b;}\n",
       ".cython.score-221 {background-color: #FFFF0b;}\n",
       ".cython.score-222 {background-color: #FFFF0a;}\n",
       ".cython.score-223 {background-color: #FFFF0a;}\n",
       ".cython.score-224 {background-color: #FFFF0a;}\n",
       ".cython.score-225 {background-color: #FFFF0a;}\n",
       ".cython.score-226 {background-color: #FFFF0a;}\n",
       ".cython.score-227 {background-color: #FFFF0a;}\n",
       ".cython.score-228 {background-color: #FFFF0a;}\n",
       ".cython.score-229 {background-color: #FFFF0a;}\n",
       ".cython.score-230 {background-color: #FFFF0a;}\n",
       ".cython.score-231 {background-color: #FFFF0a;}\n",
       ".cython.score-232 {background-color: #FFFF0a;}\n",
       ".cython.score-233 {background-color: #FFFF0a;}\n",
       ".cython.score-234 {background-color: #FFFF0a;}\n",
       ".cython.score-235 {background-color: #FFFF0a;}\n",
       ".cython.score-236 {background-color: #FFFF0a;}\n",
       ".cython.score-237 {background-color: #FFFF0a;}\n",
       ".cython.score-238 {background-color: #FFFF0a;}\n",
       ".cython.score-239 {background-color: #FFFF0a;}\n",
       ".cython.score-240 {background-color: #FFFF0a;}\n",
       ".cython.score-241 {background-color: #FFFF0a;}\n",
       ".cython.score-242 {background-color: #FFFF0a;}\n",
       ".cython.score-243 {background-color: #FFFF0a;}\n",
       ".cython.score-244 {background-color: #FFFF0a;}\n",
       ".cython.score-245 {background-color: #FFFF0a;}\n",
       ".cython.score-246 {background-color: #FFFF09;}\n",
       ".cython.score-247 {background-color: #FFFF09;}\n",
       ".cython.score-248 {background-color: #FFFF09;}\n",
       ".cython.score-249 {background-color: #FFFF09;}\n",
       ".cython.score-250 {background-color: #FFFF09;}\n",
       ".cython.score-251 {background-color: #FFFF09;}\n",
       ".cython.score-252 {background-color: #FFFF09;}\n",
       ".cython.score-253 {background-color: #FFFF09;}\n",
       ".cython.score-254 {background-color: #FFFF09;}\n",
       ".cython .hll { background-color: #ffffcc }\n",
       ".cython  { background: #f8f8f8; }\n",
       ".cython .c { color: #408080; font-style: italic } /* Comment */\n",
       ".cython .err { border: 1px solid #FF0000 } /* Error */\n",
       ".cython .k { color: #008000; font-weight: bold } /* Keyword */\n",
       ".cython .o { color: #666666 } /* Operator */\n",
       ".cython .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n",
       ".cython .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n",
       ".cython .cp { color: #BC7A00 } /* Comment.Preproc */\n",
       ".cython .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n",
       ".cython .c1 { color: #408080; font-style: italic } /* Comment.Single */\n",
       ".cython .cs { color: #408080; font-style: italic } /* Comment.Special */\n",
       ".cython .gd { color: #A00000 } /* Generic.Deleted */\n",
       ".cython .ge { font-style: italic } /* Generic.Emph */\n",
       ".cython .gr { color: #FF0000 } /* Generic.Error */\n",
       ".cython .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n",
       ".cython .gi { color: #00A000 } /* Generic.Inserted */\n",
       ".cython .go { color: #888888 } /* Generic.Output */\n",
       ".cython .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n",
       ".cython .gs { font-weight: bold } /* Generic.Strong */\n",
       ".cython .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n",
       ".cython .gt { color: #0044DD } /* Generic.Traceback */\n",
       ".cython .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n",
       ".cython .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n",
       ".cython .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n",
       ".cython .kp { color: #008000 } /* Keyword.Pseudo */\n",
       ".cython .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n",
       ".cython .kt { color: #B00040 } /* Keyword.Type */\n",
       ".cython .m { color: #666666 } /* Literal.Number */\n",
       ".cython .s { color: #BA2121 } /* Literal.String */\n",
       ".cython .na { color: #7D9029 } /* Name.Attribute */\n",
       ".cython .nb { color: #008000 } /* Name.Builtin */\n",
       ".cython .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n",
       ".cython .no { color: #880000 } /* Name.Constant */\n",
       ".cython .nd { color: #AA22FF } /* Name.Decorator */\n",
       ".cython .ni { color: #999999; font-weight: bold } /* Name.Entity */\n",
       ".cython .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n",
       ".cython .nf { color: #0000FF } /* Name.Function */\n",
       ".cython .nl { color: #A0A000 } /* Name.Label */\n",
       ".cython .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n",
       ".cython .nt { color: #008000; font-weight: bold } /* Name.Tag */\n",
       ".cython .nv { color: #19177C } /* Name.Variable */\n",
       ".cython .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n",
       ".cython .w { color: #bbbbbb } /* Text.Whitespace */\n",
       ".cython .mb { color: #666666 } /* Literal.Number.Bin */\n",
       ".cython .mf { color: #666666 } /* Literal.Number.Float */\n",
       ".cython .mh { color: #666666 } /* Literal.Number.Hex */\n",
       ".cython .mi { color: #666666 } /* Literal.Number.Integer */\n",
       ".cython .mo { color: #666666 } /* Literal.Number.Oct */\n",
       ".cython .sa { color: #BA2121 } /* Literal.String.Affix */\n",
       ".cython .sb { color: #BA2121 } /* Literal.String.Backtick */\n",
       ".cython .sc { color: #BA2121 } /* Literal.String.Char */\n",
       ".cython .dl { color: #BA2121 } /* Literal.String.Delimiter */\n",
       ".cython .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n",
       ".cython .s2 { color: #BA2121 } /* Literal.String.Double */\n",
       ".cython .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n",
       ".cython .sh { color: #BA2121 } /* Literal.String.Heredoc */\n",
       ".cython .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n",
       ".cython .sx { color: #008000 } /* Literal.String.Other */\n",
       ".cython .sr { color: #BB6688 } /* Literal.String.Regex */\n",
       ".cython .s1 { color: #BA2121 } /* Literal.String.Single */\n",
       ".cython .ss { color: #19177C } /* Literal.String.Symbol */\n",
       ".cython .bp { color: #008000 } /* Name.Builtin.Pseudo */\n",
       ".cython .fm { color: #0000FF } /* Name.Function.Magic */\n",
       ".cython .vc { color: #19177C } /* Name.Variable.Class */\n",
       ".cython .vg { color: #19177C } /* Name.Variable.Global */\n",
       ".cython .vi { color: #19177C } /* Name.Variable.Instance */\n",
       ".cython .vm { color: #19177C } /* Name.Variable.Magic */\n",
       ".cython .il { color: #666666 } /* Literal.Number.Integer.Long */\n",
       "    </style>\n",
       "</head>\n",
       "<body class=\"cython\">\n",
       "<p><span style=\"border-bottom: solid 1px grey;\">Generated by Cython 0.29.20</span></p>\n",
       "<p>\n",
       "    <span style=\"background-color: #FFFF00\">Yellow lines</span> hint at Python interaction.<br />\n",
       "    Click on a line that starts with a \"<code>+</code>\" to see the C code that Cython generated for it.\n",
       "</p>\n",
       "<div class=\"cython\"><pre class=\"cython line score-8\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">1</span>: <span class=\"k\">import</span> <span class=\"nn\">random</span></pre>\n",
       "<pre class='cython code score-8 '>  __pyx_t_1 = <span class='pyx_c_api'>__Pyx_Import</span>(__pyx_n_s_random, 0, 0);<span class='error_goto'> if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_1);\n",
       "  if (<span class='py_c_api'>PyDict_SetItem</span>(__pyx_d, __pyx_n_s_random, __pyx_t_1) &lt; 0) <span class='error_goto'>__PYX_ERR(0, 1, __pyx_L1_error)</span>\n",
       "  <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_1); __pyx_t_1 = 0;\n",
       "</pre><pre class=\"cython line score-25\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">2</span>: <span class=\"k\">def</span> <span class=\"nf\">mcs_pi_cy1</span><span class=\"p\">(</span><span class=\"nb\">int</span> <span class=\"n\">n</span><span class=\"p\">):</span></pre>\n",
       "<pre class='cython code score-25 '>/* Python wrapper */\n",
       "static PyObject *__pyx_pw_46_cython_magic_f06e2f6732b65e46645f28671e6aca06_1mcs_pi_cy1(PyObject *__pyx_self, PyObject *__pyx_arg_n); /*proto*/\n",
       "static PyMethodDef __pyx_mdef_46_cython_magic_f06e2f6732b65e46645f28671e6aca06_1mcs_pi_cy1 = {\"mcs_pi_cy1\", (PyCFunction)__pyx_pw_46_cython_magic_f06e2f6732b65e46645f28671e6aca06_1mcs_pi_cy1, METH_O, 0};\n",
       "static PyObject *__pyx_pw_46_cython_magic_f06e2f6732b65e46645f28671e6aca06_1mcs_pi_cy1(PyObject *__pyx_self, PyObject *__pyx_arg_n) {\n",
       "  int __pyx_v_n;\n",
       "  PyObject *__pyx_r = 0;\n",
       "  <span class='refnanny'>__Pyx_RefNannyDeclarations</span>\n",
       "  <span class='refnanny'>__Pyx_RefNannySetupContext</span>(\"mcs_pi_cy1 (wrapper)\", 0);\n",
       "  assert(__pyx_arg_n); {\n",
       "    __pyx_v_n = <span class='pyx_c_api'>__Pyx_PyInt_As_int</span>(__pyx_arg_n); if (unlikely((__pyx_v_n == (int)-1) &amp;&amp; <span class='py_c_api'>PyErr_Occurred</span>())) <span class='error_goto'>__PYX_ERR(0, 2, __pyx_L3_error)</span>\n",
       "  }\n",
       "  goto __pyx_L4_argument_unpacking_done;\n",
       "  __pyx_L3_error:;\n",
       "  <span class='pyx_c_api'>__Pyx_AddTraceback</span>(\"_cython_magic_f06e2f6732b65e46645f28671e6aca06.mcs_pi_cy1\", __pyx_clineno, __pyx_lineno, __pyx_filename);\n",
       "  <span class='refnanny'>__Pyx_RefNannyFinishContext</span>();\n",
       "  return NULL;\n",
       "  __pyx_L4_argument_unpacking_done:;\n",
       "  __pyx_r = __pyx_pf_46_cython_magic_f06e2f6732b65e46645f28671e6aca06_mcs_pi_cy1(__pyx_self, ((int)__pyx_v_n));\n",
       "  int __pyx_lineno = 0;\n",
       "  const char *__pyx_filename = NULL;\n",
       "  int __pyx_clineno = 0;\n",
       "\n",
       "  /* function exit code */\n",
       "  <span class='refnanny'>__Pyx_RefNannyFinishContext</span>();\n",
       "  return __pyx_r;\n",
       "}\n",
       "\n",
       "static PyObject *__pyx_pf_46_cython_magic_f06e2f6732b65e46645f28671e6aca06_mcs_pi_cy1(CYTHON_UNUSED PyObject *__pyx_self, int __pyx_v_n) {\n",
       "  CYTHON_UNUSED int __pyx_v_i;\n",
       "  int __pyx_v_circle;\n",
       "  float __pyx_v_x;\n",
       "  float __pyx_v_y;\n",
       "  PyObject *__pyx_r = NULL;\n",
       "  <span class='refnanny'>__Pyx_RefNannyDeclarations</span>\n",
       "  <span class='refnanny'>__Pyx_RefNannySetupContext</span>(\"mcs_pi_cy1\", 0);\n",
       "/* … */\n",
       "  /* function exit code */\n",
       "  __pyx_L1_error:;\n",
       "  <span class='pyx_macro_api'>__Pyx_XDECREF</span>(__pyx_t_4);\n",
       "  <span class='pyx_macro_api'>__Pyx_XDECREF</span>(__pyx_t_5);\n",
       "  <span class='pyx_macro_api'>__Pyx_XDECREF</span>(__pyx_t_6);\n",
       "  <span class='pyx_c_api'>__Pyx_AddTraceback</span>(\"_cython_magic_f06e2f6732b65e46645f28671e6aca06.mcs_pi_cy1\", __pyx_clineno, __pyx_lineno, __pyx_filename);\n",
       "  __pyx_r = NULL;\n",
       "  __pyx_L0:;\n",
       "  <span class='refnanny'>__Pyx_XGIVEREF</span>(__pyx_r);\n",
       "  <span class='refnanny'>__Pyx_RefNannyFinishContext</span>();\n",
       "  return __pyx_r;\n",
       "}\n",
       "/* … */\n",
       "  __pyx_tuple_ = <span class='py_c_api'>PyTuple_Pack</span>(6, __pyx_n_s_n, __pyx_n_s_n, __pyx_n_s_i, __pyx_n_s_circle, __pyx_n_s_x, __pyx_n_s_y);<span class='error_goto'> if (unlikely(!__pyx_tuple_)) __PYX_ERR(0, 2, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_tuple_);\n",
       "  <span class='refnanny'>__Pyx_GIVEREF</span>(__pyx_tuple_);\n",
       "/* … */\n",
       "  __pyx_t_1 = PyCFunction_NewEx(&amp;__pyx_mdef_46_cython_magic_f06e2f6732b65e46645f28671e6aca06_1mcs_pi_cy1, NULL, __pyx_n_s_cython_magic_f06e2f6732b65e4664);<span class='error_goto'> if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 2, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_1);\n",
       "  if (<span class='py_c_api'>PyDict_SetItem</span>(__pyx_d, __pyx_n_s_mcs_pi_cy1, __pyx_t_1) &lt; 0) <span class='error_goto'>__PYX_ERR(0, 2, __pyx_L1_error)</span>\n",
       "  <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_1); __pyx_t_1 = 0;\n",
       "</pre><pre class=\"cython line score-0\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">3</span>:     <span class=\"k\">cdef</span> <span class=\"kt\">int</span> <span class=\"nf\">i</span><span class=\"p\">,</span> <span class=\"nf\">circle</span> <span class=\"o\">=</span> <span class=\"mf\">0</span></pre>\n",
       "<pre class='cython code score-0 '>  __pyx_v_circle = 0;\n",
       "</pre><pre class=\"cython line score-0\">&#xA0;<span class=\"\">4</span>:     <span class=\"k\">cdef</span> <span class=\"kt\">float</span> <span class=\"nf\">x</span><span class=\"p\">,</span> <span class=\"nf\">y</span></pre>\n",
       "<pre class=\"cython line score-0\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">5</span>:     <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">n</span><span class=\"p\">):</span></pre>\n",
       "<pre class='cython code score-0 '>  __pyx_t_1 = __pyx_v_n;\n",
       "  __pyx_t_2 = __pyx_t_1;\n",
       "  for (__pyx_t_3 = 0; __pyx_t_3 &lt; __pyx_t_2; __pyx_t_3+=1) {\n",
       "    __pyx_v_i = __pyx_t_3;\n",
       "</pre><pre class=\"cython line score-64\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">6</span>:         <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"p\">(),</span> <span class=\"n\">random</span><span class=\"o\">.</span><span class=\"n\">random</span><span class=\"p\">()</span></pre>\n",
       "<pre class='cython code score-64 '>    <span class='pyx_c_api'>__Pyx_GetModuleGlobalName</span>(__pyx_t_5, __pyx_n_s_random);<span class='error_goto'> if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 6, __pyx_L1_error)</span>\n",
       "    <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_5);\n",
       "    __pyx_t_6 = <span class='pyx_c_api'>__Pyx_PyObject_GetAttrStr</span>(__pyx_t_5, __pyx_n_s_random);<span class='error_goto'> if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 6, __pyx_L1_error)</span>\n",
       "    <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_6);\n",
       "    <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_5); __pyx_t_5 = 0;\n",
       "    __pyx_t_5 = NULL;\n",
       "    if (CYTHON_UNPACK_METHODS &amp;&amp; unlikely(<span class='py_c_api'>PyMethod_Check</span>(__pyx_t_6))) {\n",
       "      __pyx_t_5 = <span class='py_macro_api'>PyMethod_GET_SELF</span>(__pyx_t_6);\n",
       "      if (likely(__pyx_t_5)) {\n",
       "        PyObject* function = <span class='py_macro_api'>PyMethod_GET_FUNCTION</span>(__pyx_t_6);\n",
       "        <span class='pyx_macro_api'>__Pyx_INCREF</span>(__pyx_t_5);\n",
       "        <span class='pyx_macro_api'>__Pyx_INCREF</span>(function);\n",
       "        <span class='pyx_macro_api'>__Pyx_DECREF_SET</span>(__pyx_t_6, function);\n",
       "      }\n",
       "    }\n",
       "    __pyx_t_4 = (__pyx_t_5) ? <span class='pyx_c_api'>__Pyx_PyObject_CallOneArg</span>(__pyx_t_6, __pyx_t_5) : <span class='pyx_c_api'>__Pyx_PyObject_CallNoArg</span>(__pyx_t_6);\n",
       "    <span class='pyx_macro_api'>__Pyx_XDECREF</span>(__pyx_t_5); __pyx_t_5 = 0;\n",
       "    if (unlikely(!__pyx_t_4)) <span class='error_goto'>__PYX_ERR(0, 6, __pyx_L1_error)</span>\n",
       "    <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_4);\n",
       "    <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_6); __pyx_t_6 = 0;\n",
       "    __pyx_t_7 = __pyx_<span class='py_c_api'>PyFloat_AsFloat</span>(__pyx_t_4); if (unlikely((__pyx_t_7 == (float)-1) &amp;&amp; <span class='py_c_api'>PyErr_Occurred</span>())) <span class='error_goto'>__PYX_ERR(0, 6, __pyx_L1_error)</span>\n",
       "    <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_4); __pyx_t_4 = 0;\n",
       "    <span class='pyx_c_api'>__Pyx_GetModuleGlobalName</span>(__pyx_t_6, __pyx_n_s_random);<span class='error_goto'> if (unlikely(!__pyx_t_6)) __PYX_ERR(0, 6, __pyx_L1_error)</span>\n",
       "    <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_6);\n",
       "    __pyx_t_5 = <span class='pyx_c_api'>__Pyx_PyObject_GetAttrStr</span>(__pyx_t_6, __pyx_n_s_random);<span class='error_goto'> if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 6, __pyx_L1_error)</span>\n",
       "    <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_5);\n",
       "    <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_6); __pyx_t_6 = 0;\n",
       "    __pyx_t_6 = NULL;\n",
       "    if (CYTHON_UNPACK_METHODS &amp;&amp; unlikely(<span class='py_c_api'>PyMethod_Check</span>(__pyx_t_5))) {\n",
       "      __pyx_t_6 = <span class='py_macro_api'>PyMethod_GET_SELF</span>(__pyx_t_5);\n",
       "      if (likely(__pyx_t_6)) {\n",
       "        PyObject* function = <span class='py_macro_api'>PyMethod_GET_FUNCTION</span>(__pyx_t_5);\n",
       "        <span class='pyx_macro_api'>__Pyx_INCREF</span>(__pyx_t_6);\n",
       "        <span class='pyx_macro_api'>__Pyx_INCREF</span>(function);\n",
       "        <span class='pyx_macro_api'>__Pyx_DECREF_SET</span>(__pyx_t_5, function);\n",
       "      }\n",
       "    }\n",
       "    __pyx_t_4 = (__pyx_t_6) ? <span class='pyx_c_api'>__Pyx_PyObject_CallOneArg</span>(__pyx_t_5, __pyx_t_6) : <span class='pyx_c_api'>__Pyx_PyObject_CallNoArg</span>(__pyx_t_5);\n",
       "    <span class='pyx_macro_api'>__Pyx_XDECREF</span>(__pyx_t_6); __pyx_t_6 = 0;\n",
       "    if (unlikely(!__pyx_t_4)) <span class='error_goto'>__PYX_ERR(0, 6, __pyx_L1_error)</span>\n",
       "    <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_4);\n",
       "    <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_5); __pyx_t_5 = 0;\n",
       "    __pyx_t_8 = __pyx_<span class='py_c_api'>PyFloat_AsFloat</span>(__pyx_t_4); if (unlikely((__pyx_t_8 == (float)-1) &amp;&amp; <span class='py_c_api'>PyErr_Occurred</span>())) <span class='error_goto'>__PYX_ERR(0, 6, __pyx_L1_error)</span>\n",
       "    <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_4); __pyx_t_4 = 0;\n",
       "    __pyx_v_x = __pyx_t_7;\n",
       "    __pyx_v_y = __pyx_t_8;\n",
       "</pre><pre class=\"cython line score-0\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">7</span>:         <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">x</span> <span class=\"o\">**</span> <span class=\"mf\">2</span> <span class=\"o\">+</span> <span class=\"n\">y</span> <span class=\"o\">**</span> <span class=\"mf\">2</span><span class=\"p\">)</span> <span class=\"o\">**</span> <span class=\"mf\">0.5</span> <span class=\"o\">&lt;=</span> <span class=\"mf\">1</span><span class=\"p\">:</span></pre>\n",
       "<pre class='cython code score-0 '>    __pyx_t_9 = ((pow(((double)(powf(__pyx_v_x, 2.0) + powf(__pyx_v_y, 2.0))), 0.5) &lt;= 1.0) != 0);\n",
       "    if (__pyx_t_9) {\n",
       "/* … */\n",
       "    }\n",
       "  }\n",
       "</pre><pre class=\"cython line score-0\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">8</span>:             <span class=\"n\">circle</span> <span class=\"o\">+=</span> <span class=\"mf\">1</span></pre>\n",
       "<pre class='cython code score-0 '>      __pyx_v_circle = (__pyx_v_circle + 1);\n",
       "</pre><pre class=\"cython line score-11\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">9</span>:     <span class=\"k\">return</span> <span class=\"p\">(</span><span class=\"mf\">4</span> <span class=\"o\">*</span> <span class=\"n\">circle</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"n\">n</span></pre>\n",
       "<pre class='cython code score-11 '>  <span class='pyx_macro_api'>__Pyx_XDECREF</span>(__pyx_r);\n",
       "  __pyx_t_10 = (4 * __pyx_v_circle);\n",
       "  if (unlikely(__pyx_v_n == 0)) {\n",
       "    <span class='py_c_api'>PyErr_SetString</span>(PyExc_ZeroDivisionError, \"float division\");\n",
       "    <span class='error_goto'>__PYX_ERR(0, 9, __pyx_L1_error)</span>\n",
       "  }\n",
       "  __pyx_t_4 = <span class='py_c_api'>PyFloat_FromDouble</span>((((double)__pyx_t_10) / ((double)__pyx_v_n)));<span class='error_goto'> if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 9, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_4);\n",
       "  __pyx_r = __pyx_t_4;\n",
       "  __pyx_t_4 = 0;\n",
       "  goto __pyx_L0;\n",
       "</pre></div></body></html>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 93,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%%cython -a\n",
    "import random\n",
    "def mcs_pi_cy1(int n):\n",
    "    cdef int i, circle = 0\n",
    "    cdef float x, y\n",
    "    for i in range(n):\n",
    "        x, y = random.random(), random.random()\n",
    "        if (x ** 2 + y ** 2) ** 0.5 <= 1:\n",
    "            circle += 1\n",
    "    return (4 * circle) / n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 94,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 969 ms, sys: 10.8 ms, total: 980 ms\n",
      "Wall time: 979 ms\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "3.1416176"
      ]
     },
     "execution_count": 94,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time mcs_pi_cy1(n)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 95,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<!DOCTYPE html>\n",
       "<!-- Generated by Cython 0.29.20 -->\n",
       "<html>\n",
       "<head>\n",
       "    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n",
       "    <title>Cython: _cython_magic_9c57b9e08316eebb9f67411012db7055.pyx</title>\n",
       "    <style type=\"text/css\">\n",
       "    \n",
       "body.cython { font-family: courier; font-size: 12; }\n",
       "\n",
       ".cython.tag  {  }\n",
       ".cython.line { margin: 0em }\n",
       ".cython.code { font-size: 9; color: #444444; display: none; margin: 0px 0px 0px 8px; border-left: 8px none; }\n",
       "\n",
       ".cython.line .run { background-color: #B0FFB0; }\n",
       ".cython.line .mis { background-color: #FFB0B0; }\n",
       ".cython.code.run  { border-left: 8px solid #B0FFB0; }\n",
       ".cython.code.mis  { border-left: 8px solid #FFB0B0; }\n",
       "\n",
       ".cython.code .py_c_api  { color: red; }\n",
       ".cython.code .py_macro_api  { color: #FF7000; }\n",
       ".cython.code .pyx_c_api  { color: #FF3000; }\n",
       ".cython.code .pyx_macro_api  { color: #FF7000; }\n",
       ".cython.code .refnanny  { color: #FFA000; }\n",
       ".cython.code .trace  { color: #FFA000; }\n",
       ".cython.code .error_goto  { color: #FFA000; }\n",
       "\n",
       ".cython.code .coerce  { color: #008000; border: 1px dotted #008000 }\n",
       ".cython.code .py_attr { color: #FF0000; font-weight: bold; }\n",
       ".cython.code .c_attr  { color: #0000FF; }\n",
       ".cython.code .py_call { color: #FF0000; font-weight: bold; }\n",
       ".cython.code .c_call  { color: #0000FF; }\n",
       "\n",
       ".cython.score-0 {background-color: #FFFFff;}\n",
       ".cython.score-1 {background-color: #FFFFe7;}\n",
       ".cython.score-2 {background-color: #FFFFd4;}\n",
       ".cython.score-3 {background-color: #FFFFc4;}\n",
       ".cython.score-4 {background-color: #FFFFb6;}\n",
       ".cython.score-5 {background-color: #FFFFaa;}\n",
       ".cython.score-6 {background-color: #FFFF9f;}\n",
       ".cython.score-7 {background-color: #FFFF96;}\n",
       ".cython.score-8 {background-color: #FFFF8d;}\n",
       ".cython.score-9 {background-color: #FFFF86;}\n",
       ".cython.score-10 {background-color: #FFFF7f;}\n",
       ".cython.score-11 {background-color: #FFFF79;}\n",
       ".cython.score-12 {background-color: #FFFF73;}\n",
       ".cython.score-13 {background-color: #FFFF6e;}\n",
       ".cython.score-14 {background-color: #FFFF6a;}\n",
       ".cython.score-15 {background-color: #FFFF66;}\n",
       ".cython.score-16 {background-color: #FFFF62;}\n",
       ".cython.score-17 {background-color: #FFFF5e;}\n",
       ".cython.score-18 {background-color: #FFFF5b;}\n",
       ".cython.score-19 {background-color: #FFFF57;}\n",
       ".cython.score-20 {background-color: #FFFF55;}\n",
       ".cython.score-21 {background-color: #FFFF52;}\n",
       ".cython.score-22 {background-color: #FFFF4f;}\n",
       ".cython.score-23 {background-color: #FFFF4d;}\n",
       ".cython.score-24 {background-color: #FFFF4b;}\n",
       ".cython.score-25 {background-color: #FFFF48;}\n",
       ".cython.score-26 {background-color: #FFFF46;}\n",
       ".cython.score-27 {background-color: #FFFF44;}\n",
       ".cython.score-28 {background-color: #FFFF43;}\n",
       ".cython.score-29 {background-color: #FFFF41;}\n",
       ".cython.score-30 {background-color: #FFFF3f;}\n",
       ".cython.score-31 {background-color: #FFFF3e;}\n",
       ".cython.score-32 {background-color: #FFFF3c;}\n",
       ".cython.score-33 {background-color: #FFFF3b;}\n",
       ".cython.score-34 {background-color: #FFFF39;}\n",
       ".cython.score-35 {background-color: #FFFF38;}\n",
       ".cython.score-36 {background-color: #FFFF37;}\n",
       ".cython.score-37 {background-color: #FFFF36;}\n",
       ".cython.score-38 {background-color: #FFFF35;}\n",
       ".cython.score-39 {background-color: #FFFF34;}\n",
       ".cython.score-40 {background-color: #FFFF33;}\n",
       ".cython.score-41 {background-color: #FFFF32;}\n",
       ".cython.score-42 {background-color: #FFFF31;}\n",
       ".cython.score-43 {background-color: #FFFF30;}\n",
       ".cython.score-44 {background-color: #FFFF2f;}\n",
       ".cython.score-45 {background-color: #FFFF2e;}\n",
       ".cython.score-46 {background-color: #FFFF2d;}\n",
       ".cython.score-47 {background-color: #FFFF2c;}\n",
       ".cython.score-48 {background-color: #FFFF2b;}\n",
       ".cython.score-49 {background-color: #FFFF2b;}\n",
       ".cython.score-50 {background-color: #FFFF2a;}\n",
       ".cython.score-51 {background-color: #FFFF29;}\n",
       ".cython.score-52 {background-color: #FFFF29;}\n",
       ".cython.score-53 {background-color: #FFFF28;}\n",
       ".cython.score-54 {background-color: #FFFF27;}\n",
       ".cython.score-55 {background-color: #FFFF27;}\n",
       ".cython.score-56 {background-color: #FFFF26;}\n",
       ".cython.score-57 {background-color: #FFFF26;}\n",
       ".cython.score-58 {background-color: #FFFF25;}\n",
       ".cython.score-59 {background-color: #FFFF24;}\n",
       ".cython.score-60 {background-color: #FFFF24;}\n",
       ".cython.score-61 {background-color: #FFFF23;}\n",
       ".cython.score-62 {background-color: #FFFF23;}\n",
       ".cython.score-63 {background-color: #FFFF22;}\n",
       ".cython.score-64 {background-color: #FFFF22;}\n",
       ".cython.score-65 {background-color: #FFFF22;}\n",
       ".cython.score-66 {background-color: #FFFF21;}\n",
       ".cython.score-67 {background-color: #FFFF21;}\n",
       ".cython.score-68 {background-color: #FFFF20;}\n",
       ".cython.score-69 {background-color: #FFFF20;}\n",
       ".cython.score-70 {background-color: #FFFF1f;}\n",
       ".cython.score-71 {background-color: #FFFF1f;}\n",
       ".cython.score-72 {background-color: #FFFF1f;}\n",
       ".cython.score-73 {background-color: #FFFF1e;}\n",
       ".cython.score-74 {background-color: #FFFF1e;}\n",
       ".cython.score-75 {background-color: #FFFF1e;}\n",
       ".cython.score-76 {background-color: #FFFF1d;}\n",
       ".cython.score-77 {background-color: #FFFF1d;}\n",
       ".cython.score-78 {background-color: #FFFF1c;}\n",
       ".cython.score-79 {background-color: #FFFF1c;}\n",
       ".cython.score-80 {background-color: #FFFF1c;}\n",
       ".cython.score-81 {background-color: #FFFF1c;}\n",
       ".cython.score-82 {background-color: #FFFF1b;}\n",
       ".cython.score-83 {background-color: #FFFF1b;}\n",
       ".cython.score-84 {background-color: #FFFF1b;}\n",
       ".cython.score-85 {background-color: #FFFF1a;}\n",
       ".cython.score-86 {background-color: #FFFF1a;}\n",
       ".cython.score-87 {background-color: #FFFF1a;}\n",
       ".cython.score-88 {background-color: #FFFF1a;}\n",
       ".cython.score-89 {background-color: #FFFF19;}\n",
       ".cython.score-90 {background-color: #FFFF19;}\n",
       ".cython.score-91 {background-color: #FFFF19;}\n",
       ".cython.score-92 {background-color: #FFFF19;}\n",
       ".cython.score-93 {background-color: #FFFF18;}\n",
       ".cython.score-94 {background-color: #FFFF18;}\n",
       ".cython.score-95 {background-color: #FFFF18;}\n",
       ".cython.score-96 {background-color: #FFFF18;}\n",
       ".cython.score-97 {background-color: #FFFF17;}\n",
       ".cython.score-98 {background-color: #FFFF17;}\n",
       ".cython.score-99 {background-color: #FFFF17;}\n",
       ".cython.score-100 {background-color: #FFFF17;}\n",
       ".cython.score-101 {background-color: #FFFF16;}\n",
       ".cython.score-102 {background-color: #FFFF16;}\n",
       ".cython.score-103 {background-color: #FFFF16;}\n",
       ".cython.score-104 {background-color: #FFFF16;}\n",
       ".cython.score-105 {background-color: #FFFF16;}\n",
       ".cython.score-106 {background-color: #FFFF15;}\n",
       ".cython.score-107 {background-color: #FFFF15;}\n",
       ".cython.score-108 {background-color: #FFFF15;}\n",
       ".cython.score-109 {background-color: #FFFF15;}\n",
       ".cython.score-110 {background-color: #FFFF15;}\n",
       ".cython.score-111 {background-color: #FFFF15;}\n",
       ".cython.score-112 {background-color: #FFFF14;}\n",
       ".cython.score-113 {background-color: #FFFF14;}\n",
       ".cython.score-114 {background-color: #FFFF14;}\n",
       ".cython.score-115 {background-color: #FFFF14;}\n",
       ".cython.score-116 {background-color: #FFFF14;}\n",
       ".cython.score-117 {background-color: #FFFF14;}\n",
       ".cython.score-118 {background-color: #FFFF13;}\n",
       ".cython.score-119 {background-color: #FFFF13;}\n",
       ".cython.score-120 {background-color: #FFFF13;}\n",
       ".cython.score-121 {background-color: #FFFF13;}\n",
       ".cython.score-122 {background-color: #FFFF13;}\n",
       ".cython.score-123 {background-color: #FFFF13;}\n",
       ".cython.score-124 {background-color: #FFFF13;}\n",
       ".cython.score-125 {background-color: #FFFF12;}\n",
       ".cython.score-126 {background-color: #FFFF12;}\n",
       ".cython.score-127 {background-color: #FFFF12;}\n",
       ".cython.score-128 {background-color: #FFFF12;}\n",
       ".cython.score-129 {background-color: #FFFF12;}\n",
       ".cython.score-130 {background-color: #FFFF12;}\n",
       ".cython.score-131 {background-color: #FFFF12;}\n",
       ".cython.score-132 {background-color: #FFFF11;}\n",
       ".cython.score-133 {background-color: #FFFF11;}\n",
       ".cython.score-134 {background-color: #FFFF11;}\n",
       ".cython.score-135 {background-color: #FFFF11;}\n",
       ".cython.score-136 {background-color: #FFFF11;}\n",
       ".cython.score-137 {background-color: #FFFF11;}\n",
       ".cython.score-138 {background-color: #FFFF11;}\n",
       ".cython.score-139 {background-color: #FFFF11;}\n",
       ".cython.score-140 {background-color: #FFFF11;}\n",
       ".cython.score-141 {background-color: #FFFF10;}\n",
       ".cython.score-142 {background-color: #FFFF10;}\n",
       ".cython.score-143 {background-color: #FFFF10;}\n",
       ".cython.score-144 {background-color: #FFFF10;}\n",
       ".cython.score-145 {background-color: #FFFF10;}\n",
       ".cython.score-146 {background-color: #FFFF10;}\n",
       ".cython.score-147 {background-color: #FFFF10;}\n",
       ".cython.score-148 {background-color: #FFFF10;}\n",
       ".cython.score-149 {background-color: #FFFF10;}\n",
       ".cython.score-150 {background-color: #FFFF0f;}\n",
       ".cython.score-151 {background-color: #FFFF0f;}\n",
       ".cython.score-152 {background-color: #FFFF0f;}\n",
       ".cython.score-153 {background-color: #FFFF0f;}\n",
       ".cython.score-154 {background-color: #FFFF0f;}\n",
       ".cython.score-155 {background-color: #FFFF0f;}\n",
       ".cython.score-156 {background-color: #FFFF0f;}\n",
       ".cython.score-157 {background-color: #FFFF0f;}\n",
       ".cython.score-158 {background-color: #FFFF0f;}\n",
       ".cython.score-159 {background-color: #FFFF0f;}\n",
       ".cython.score-160 {background-color: #FFFF0f;}\n",
       ".cython.score-161 {background-color: #FFFF0e;}\n",
       ".cython.score-162 {background-color: #FFFF0e;}\n",
       ".cython.score-163 {background-color: #FFFF0e;}\n",
       ".cython.score-164 {background-color: #FFFF0e;}\n",
       ".cython.score-165 {background-color: #FFFF0e;}\n",
       ".cython.score-166 {background-color: #FFFF0e;}\n",
       ".cython.score-167 {background-color: #FFFF0e;}\n",
       ".cython.score-168 {background-color: #FFFF0e;}\n",
       ".cython.score-169 {background-color: #FFFF0e;}\n",
       ".cython.score-170 {background-color: #FFFF0e;}\n",
       ".cython.score-171 {background-color: #FFFF0e;}\n",
       ".cython.score-172 {background-color: #FFFF0e;}\n",
       ".cython.score-173 {background-color: #FFFF0d;}\n",
       ".cython.score-174 {background-color: #FFFF0d;}\n",
       ".cython.score-175 {background-color: #FFFF0d;}\n",
       ".cython.score-176 {background-color: #FFFF0d;}\n",
       ".cython.score-177 {background-color: #FFFF0d;}\n",
       ".cython.score-178 {background-color: #FFFF0d;}\n",
       ".cython.score-179 {background-color: #FFFF0d;}\n",
       ".cython.score-180 {background-color: #FFFF0d;}\n",
       ".cython.score-181 {background-color: #FFFF0d;}\n",
       ".cython.score-182 {background-color: #FFFF0d;}\n",
       ".cython.score-183 {background-color: #FFFF0d;}\n",
       ".cython.score-184 {background-color: #FFFF0d;}\n",
       ".cython.score-185 {background-color: #FFFF0d;}\n",
       ".cython.score-186 {background-color: #FFFF0d;}\n",
       ".cython.score-187 {background-color: #FFFF0c;}\n",
       ".cython.score-188 {background-color: #FFFF0c;}\n",
       ".cython.score-189 {background-color: #FFFF0c;}\n",
       ".cython.score-190 {background-color: #FFFF0c;}\n",
       ".cython.score-191 {background-color: #FFFF0c;}\n",
       ".cython.score-192 {background-color: #FFFF0c;}\n",
       ".cython.score-193 {background-color: #FFFF0c;}\n",
       ".cython.score-194 {background-color: #FFFF0c;}\n",
       ".cython.score-195 {background-color: #FFFF0c;}\n",
       ".cython.score-196 {background-color: #FFFF0c;}\n",
       ".cython.score-197 {background-color: #FFFF0c;}\n",
       ".cython.score-198 {background-color: #FFFF0c;}\n",
       ".cython.score-199 {background-color: #FFFF0c;}\n",
       ".cython.score-200 {background-color: #FFFF0c;}\n",
       ".cython.score-201 {background-color: #FFFF0c;}\n",
       ".cython.score-202 {background-color: #FFFF0c;}\n",
       ".cython.score-203 {background-color: #FFFF0b;}\n",
       ".cython.score-204 {background-color: #FFFF0b;}\n",
       ".cython.score-205 {background-color: #FFFF0b;}\n",
       ".cython.score-206 {background-color: #FFFF0b;}\n",
       ".cython.score-207 {background-color: #FFFF0b;}\n",
       ".cython.score-208 {background-color: #FFFF0b;}\n",
       ".cython.score-209 {background-color: #FFFF0b;}\n",
       ".cython.score-210 {background-color: #FFFF0b;}\n",
       ".cython.score-211 {background-color: #FFFF0b;}\n",
       ".cython.score-212 {background-color: #FFFF0b;}\n",
       ".cython.score-213 {background-color: #FFFF0b;}\n",
       ".cython.score-214 {background-color: #FFFF0b;}\n",
       ".cython.score-215 {background-color: #FFFF0b;}\n",
       ".cython.score-216 {background-color: #FFFF0b;}\n",
       ".cython.score-217 {background-color: #FFFF0b;}\n",
       ".cython.score-218 {background-color: #FFFF0b;}\n",
       ".cython.score-219 {background-color: #FFFF0b;}\n",
       ".cython.score-220 {background-color: #FFFF0b;}\n",
       ".cython.score-221 {background-color: #FFFF0b;}\n",
       ".cython.score-222 {background-color: #FFFF0a;}\n",
       ".cython.score-223 {background-color: #FFFF0a;}\n",
       ".cython.score-224 {background-color: #FFFF0a;}\n",
       ".cython.score-225 {background-color: #FFFF0a;}\n",
       ".cython.score-226 {background-color: #FFFF0a;}\n",
       ".cython.score-227 {background-color: #FFFF0a;}\n",
       ".cython.score-228 {background-color: #FFFF0a;}\n",
       ".cython.score-229 {background-color: #FFFF0a;}\n",
       ".cython.score-230 {background-color: #FFFF0a;}\n",
       ".cython.score-231 {background-color: #FFFF0a;}\n",
       ".cython.score-232 {background-color: #FFFF0a;}\n",
       ".cython.score-233 {background-color: #FFFF0a;}\n",
       ".cython.score-234 {background-color: #FFFF0a;}\n",
       ".cython.score-235 {background-color: #FFFF0a;}\n",
       ".cython.score-236 {background-color: #FFFF0a;}\n",
       ".cython.score-237 {background-color: #FFFF0a;}\n",
       ".cython.score-238 {background-color: #FFFF0a;}\n",
       ".cython.score-239 {background-color: #FFFF0a;}\n",
       ".cython.score-240 {background-color: #FFFF0a;}\n",
       ".cython.score-241 {background-color: #FFFF0a;}\n",
       ".cython.score-242 {background-color: #FFFF0a;}\n",
       ".cython.score-243 {background-color: #FFFF0a;}\n",
       ".cython.score-244 {background-color: #FFFF0a;}\n",
       ".cython.score-245 {background-color: #FFFF0a;}\n",
       ".cython.score-246 {background-color: #FFFF09;}\n",
       ".cython.score-247 {background-color: #FFFF09;}\n",
       ".cython.score-248 {background-color: #FFFF09;}\n",
       ".cython.score-249 {background-color: #FFFF09;}\n",
       ".cython.score-250 {background-color: #FFFF09;}\n",
       ".cython.score-251 {background-color: #FFFF09;}\n",
       ".cython.score-252 {background-color: #FFFF09;}\n",
       ".cython.score-253 {background-color: #FFFF09;}\n",
       ".cython.score-254 {background-color: #FFFF09;}\n",
       ".cython .hll { background-color: #ffffcc }\n",
       ".cython  { background: #f8f8f8; }\n",
       ".cython .c { color: #408080; font-style: italic } /* Comment */\n",
       ".cython .err { border: 1px solid #FF0000 } /* Error */\n",
       ".cython .k { color: #008000; font-weight: bold } /* Keyword */\n",
       ".cython .o { color: #666666 } /* Operator */\n",
       ".cython .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n",
       ".cython .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n",
       ".cython .cp { color: #BC7A00 } /* Comment.Preproc */\n",
       ".cython .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n",
       ".cython .c1 { color: #408080; font-style: italic } /* Comment.Single */\n",
       ".cython .cs { color: #408080; font-style: italic } /* Comment.Special */\n",
       ".cython .gd { color: #A00000 } /* Generic.Deleted */\n",
       ".cython .ge { font-style: italic } /* Generic.Emph */\n",
       ".cython .gr { color: #FF0000 } /* Generic.Error */\n",
       ".cython .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n",
       ".cython .gi { color: #00A000 } /* Generic.Inserted */\n",
       ".cython .go { color: #888888 } /* Generic.Output */\n",
       ".cython .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n",
       ".cython .gs { font-weight: bold } /* Generic.Strong */\n",
       ".cython .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n",
       ".cython .gt { color: #0044DD } /* Generic.Traceback */\n",
       ".cython .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n",
       ".cython .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n",
       ".cython .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n",
       ".cython .kp { color: #008000 } /* Keyword.Pseudo */\n",
       ".cython .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n",
       ".cython .kt { color: #B00040 } /* Keyword.Type */\n",
       ".cython .m { color: #666666 } /* Literal.Number */\n",
       ".cython .s { color: #BA2121 } /* Literal.String */\n",
       ".cython .na { color: #7D9029 } /* Name.Attribute */\n",
       ".cython .nb { color: #008000 } /* Name.Builtin */\n",
       ".cython .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n",
       ".cython .no { color: #880000 } /* Name.Constant */\n",
       ".cython .nd { color: #AA22FF } /* Name.Decorator */\n",
       ".cython .ni { color: #999999; font-weight: bold } /* Name.Entity */\n",
       ".cython .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n",
       ".cython .nf { color: #0000FF } /* Name.Function */\n",
       ".cython .nl { color: #A0A000 } /* Name.Label */\n",
       ".cython .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n",
       ".cython .nt { color: #008000; font-weight: bold } /* Name.Tag */\n",
       ".cython .nv { color: #19177C } /* Name.Variable */\n",
       ".cython .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n",
       ".cython .w { color: #bbbbbb } /* Text.Whitespace */\n",
       ".cython .mb { color: #666666 } /* Literal.Number.Bin */\n",
       ".cython .mf { color: #666666 } /* Literal.Number.Float */\n",
       ".cython .mh { color: #666666 } /* Literal.Number.Hex */\n",
       ".cython .mi { color: #666666 } /* Literal.Number.Integer */\n",
       ".cython .mo { color: #666666 } /* Literal.Number.Oct */\n",
       ".cython .sa { color: #BA2121 } /* Literal.String.Affix */\n",
       ".cython .sb { color: #BA2121 } /* Literal.String.Backtick */\n",
       ".cython .sc { color: #BA2121 } /* Literal.String.Char */\n",
       ".cython .dl { color: #BA2121 } /* Literal.String.Delimiter */\n",
       ".cython .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n",
       ".cython .s2 { color: #BA2121 } /* Literal.String.Double */\n",
       ".cython .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n",
       ".cython .sh { color: #BA2121 } /* Literal.String.Heredoc */\n",
       ".cython .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n",
       ".cython .sx { color: #008000 } /* Literal.String.Other */\n",
       ".cython .sr { color: #BB6688 } /* Literal.String.Regex */\n",
       ".cython .s1 { color: #BA2121 } /* Literal.String.Single */\n",
       ".cython .ss { color: #19177C } /* Literal.String.Symbol */\n",
       ".cython .bp { color: #008000 } /* Name.Builtin.Pseudo */\n",
       ".cython .fm { color: #0000FF } /* Name.Function.Magic */\n",
       ".cython .vc { color: #19177C } /* Name.Variable.Class */\n",
       ".cython .vg { color: #19177C } /* Name.Variable.Global */\n",
       ".cython .vi { color: #19177C } /* Name.Variable.Instance */\n",
       ".cython .vm { color: #19177C } /* Name.Variable.Magic */\n",
       ".cython .il { color: #666666 } /* Literal.Number.Integer.Long */\n",
       "    </style>\n",
       "</head>\n",
       "<body class=\"cython\">\n",
       "<p><span style=\"border-bottom: solid 1px grey;\">Generated by Cython 0.29.20</span></p>\n",
       "<p>\n",
       "    <span style=\"background-color: #FFFF00\">Yellow lines</span> hint at Python interaction.<br />\n",
       "    Click on a line that starts with a \"<code>+</code>\" to see the C code that Cython generated for it.\n",
       "</p>\n",
       "<div class=\"cython\"><pre class=\"cython line score-0\">&#xA0;<span class=\"\">01</span>: <span class=\"k\">from</span> <span class=\"nn\">libc.stdlib</span> <span class=\"k\">cimport</span> <span class=\"n\">rand</span></pre>\n",
       "<pre class=\"cython line score-0\">&#xA0;<span class=\"\">02</span>: <span class=\"k\">cdef</span> <span class=\"kr\">extern</span> <span class=\"k\">from</span> <span class=\"s\">&#39;limits.h&#39;</span><span class=\"p\">:</span></pre>\n",
       "<pre class=\"cython line score-0\">&#xA0;<span class=\"\">03</span>:     <span class=\"nb\">int</span> <span class=\"n\">INT_MAX</span></pre>\n",
       "<pre class=\"cython line score-23\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">04</span>: <span class=\"k\">def</span> <span class=\"nf\">mcs_pi_cy2</span><span class=\"p\">(</span><span class=\"nb\">int</span> <span class=\"n\">n</span><span class=\"p\">):</span></pre>\n",
       "<pre class='cython code score-23 '>/* Python wrapper */\n",
       "static PyObject *__pyx_pw_46_cython_magic_9c57b9e08316eebb9f67411012db7055_1mcs_pi_cy2(PyObject *__pyx_self, PyObject *__pyx_arg_n); /*proto*/\n",
       "static PyMethodDef __pyx_mdef_46_cython_magic_9c57b9e08316eebb9f67411012db7055_1mcs_pi_cy2 = {\"mcs_pi_cy2\", (PyCFunction)__pyx_pw_46_cython_magic_9c57b9e08316eebb9f67411012db7055_1mcs_pi_cy2, METH_O, 0};\n",
       "static PyObject *__pyx_pw_46_cython_magic_9c57b9e08316eebb9f67411012db7055_1mcs_pi_cy2(PyObject *__pyx_self, PyObject *__pyx_arg_n) {\n",
       "  int __pyx_v_n;\n",
       "  PyObject *__pyx_r = 0;\n",
       "  <span class='refnanny'>__Pyx_RefNannyDeclarations</span>\n",
       "  <span class='refnanny'>__Pyx_RefNannySetupContext</span>(\"mcs_pi_cy2 (wrapper)\", 0);\n",
       "  assert(__pyx_arg_n); {\n",
       "    __pyx_v_n = <span class='pyx_c_api'>__Pyx_PyInt_As_int</span>(__pyx_arg_n); if (unlikely((__pyx_v_n == (int)-1) &amp;&amp; <span class='py_c_api'>PyErr_Occurred</span>())) <span class='error_goto'>__PYX_ERR(0, 4, __pyx_L3_error)</span>\n",
       "  }\n",
       "  goto __pyx_L4_argument_unpacking_done;\n",
       "  __pyx_L3_error:;\n",
       "  <span class='pyx_c_api'>__Pyx_AddTraceback</span>(\"_cython_magic_9c57b9e08316eebb9f67411012db7055.mcs_pi_cy2\", __pyx_clineno, __pyx_lineno, __pyx_filename);\n",
       "  <span class='refnanny'>__Pyx_RefNannyFinishContext</span>();\n",
       "  return NULL;\n",
       "  __pyx_L4_argument_unpacking_done:;\n",
       "  __pyx_r = __pyx_pf_46_cython_magic_9c57b9e08316eebb9f67411012db7055_mcs_pi_cy2(__pyx_self, ((int)__pyx_v_n));\n",
       "  int __pyx_lineno = 0;\n",
       "  const char *__pyx_filename = NULL;\n",
       "  int __pyx_clineno = 0;\n",
       "\n",
       "  /* function exit code */\n",
       "  <span class='refnanny'>__Pyx_RefNannyFinishContext</span>();\n",
       "  return __pyx_r;\n",
       "}\n",
       "\n",
       "static PyObject *__pyx_pf_46_cython_magic_9c57b9e08316eebb9f67411012db7055_mcs_pi_cy2(CYTHON_UNUSED PyObject *__pyx_self, int __pyx_v_n) {\n",
       "  CYTHON_UNUSED int __pyx_v_i;\n",
       "  int __pyx_v_circle;\n",
       "  float __pyx_v_x;\n",
       "  float __pyx_v_y;\n",
       "  PyObject *__pyx_r = NULL;\n",
       "  <span class='refnanny'>__Pyx_RefNannyDeclarations</span>\n",
       "  <span class='refnanny'>__Pyx_RefNannySetupContext</span>(\"mcs_pi_cy2\", 0);\n",
       "/* … */\n",
       "  /* function exit code */\n",
       "  __pyx_L1_error:;\n",
       "  <span class='pyx_macro_api'>__Pyx_XDECREF</span>(__pyx_t_9);\n",
       "  <span class='pyx_c_api'>__Pyx_AddTraceback</span>(\"_cython_magic_9c57b9e08316eebb9f67411012db7055.mcs_pi_cy2\", __pyx_clineno, __pyx_lineno, __pyx_filename);\n",
       "  __pyx_r = NULL;\n",
       "  __pyx_L0:;\n",
       "  <span class='refnanny'>__Pyx_XGIVEREF</span>(__pyx_r);\n",
       "  <span class='refnanny'>__Pyx_RefNannyFinishContext</span>();\n",
       "  return __pyx_r;\n",
       "}\n",
       "/* … */\n",
       "  __pyx_tuple_ = <span class='py_c_api'>PyTuple_Pack</span>(6, __pyx_n_s_n, __pyx_n_s_n, __pyx_n_s_i, __pyx_n_s_circle, __pyx_n_s_x, __pyx_n_s_y);<span class='error_goto'> if (unlikely(!__pyx_tuple_)) __PYX_ERR(0, 4, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_tuple_);\n",
       "  <span class='refnanny'>__Pyx_GIVEREF</span>(__pyx_tuple_);\n",
       "/* … */\n",
       "  __pyx_t_1 = PyCFunction_NewEx(&amp;__pyx_mdef_46_cython_magic_9c57b9e08316eebb9f67411012db7055_1mcs_pi_cy2, NULL, __pyx_n_s_cython_magic_9c57b9e08316eebb9f);<span class='error_goto'> if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 4, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_1);\n",
       "  if (<span class='py_c_api'>PyDict_SetItem</span>(__pyx_d, __pyx_n_s_mcs_pi_cy2, __pyx_t_1) &lt; 0) <span class='error_goto'>__PYX_ERR(0, 4, __pyx_L1_error)</span>\n",
       "  <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_1); __pyx_t_1 = 0;\n",
       "</pre><pre class=\"cython line score-0\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">05</span>:     <span class=\"k\">cdef</span> <span class=\"kt\">int</span> <span class=\"nf\">i</span><span class=\"p\">,</span> <span class=\"nf\">circle</span> <span class=\"o\">=</span> <span class=\"mf\">0</span></pre>\n",
       "<pre class='cython code score-0 '>  __pyx_v_circle = 0;\n",
       "</pre><pre class=\"cython line score-0\">&#xA0;<span class=\"\">06</span>:     <span class=\"k\">cdef</span> <span class=\"kt\">float</span> <span class=\"nf\">x</span><span class=\"p\">,</span> <span class=\"nf\">y</span></pre>\n",
       "<pre class=\"cython line score-0\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">07</span>:     <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">n</span><span class=\"p\">):</span></pre>\n",
       "<pre class='cython code score-0 '>  __pyx_t_1 = __pyx_v_n;\n",
       "  __pyx_t_2 = __pyx_t_1;\n",
       "  for (__pyx_t_3 = 0; __pyx_t_3 &lt; __pyx_t_2; __pyx_t_3+=1) {\n",
       "    __pyx_v_i = __pyx_t_3;\n",
       "</pre><pre class=\"cython line score-10\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">08</span>:         <span class=\"n\">x</span><span class=\"p\">,</span> <span class=\"n\">y</span> <span class=\"o\">=</span> <span class=\"n\">rand</span><span class=\"p\">()</span> <span class=\"o\">/</span> <span class=\"n\">INT_MAX</span><span class=\"p\">,</span> <span class=\"n\">rand</span><span class=\"p\">()</span> <span class=\"o\">/</span> <span class=\"n\">INT_MAX</span></pre>\n",
       "<pre class='cython code score-10 '>    __pyx_t_4 = rand();\n",
       "    if (unlikely(INT_MAX == 0)) {\n",
       "      <span class='py_c_api'>PyErr_SetString</span>(PyExc_ZeroDivisionError, \"float division\");\n",
       "      <span class='error_goto'>__PYX_ERR(0, 8, __pyx_L1_error)</span>\n",
       "    }\n",
       "    __pyx_t_5 = (((double)__pyx_t_4) / ((double)INT_MAX));\n",
       "    __pyx_t_4 = rand();\n",
       "    if (unlikely(INT_MAX == 0)) {\n",
       "      <span class='py_c_api'>PyErr_SetString</span>(PyExc_ZeroDivisionError, \"float division\");\n",
       "      <span class='error_goto'>__PYX_ERR(0, 8, __pyx_L1_error)</span>\n",
       "    }\n",
       "    __pyx_t_6 = (((double)__pyx_t_4) / ((double)INT_MAX));\n",
       "    __pyx_v_x = __pyx_t_5;\n",
       "    __pyx_v_y = __pyx_t_6;\n",
       "</pre><pre class=\"cython line score-0\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">09</span>:         <span class=\"k\">if</span> <span class=\"p\">(</span><span class=\"n\">x</span> <span class=\"o\">**</span> <span class=\"mf\">2</span> <span class=\"o\">+</span> <span class=\"n\">y</span> <span class=\"o\">**</span> <span class=\"mf\">2</span><span class=\"p\">)</span> <span class=\"o\">**</span> <span class=\"mf\">0.5</span> <span class=\"o\">&lt;=</span> <span class=\"mf\">1</span><span class=\"p\">:</span></pre>\n",
       "<pre class='cython code score-0 '>    __pyx_t_7 = ((pow(((double)(powf(__pyx_v_x, 2.0) + powf(__pyx_v_y, 2.0))), 0.5) &lt;= 1.0) != 0);\n",
       "    if (__pyx_t_7) {\n",
       "/* … */\n",
       "    }\n",
       "  }\n",
       "</pre><pre class=\"cython line score-0\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">10</span>:             <span class=\"n\">circle</span> <span class=\"o\">+=</span> <span class=\"mf\">1</span></pre>\n",
       "<pre class='cython code score-0 '>      __pyx_v_circle = (__pyx_v_circle + 1);\n",
       "</pre><pre class=\"cython line score-11\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">11</span>:     <span class=\"k\">return</span> <span class=\"p\">(</span><span class=\"mf\">4</span> <span class=\"o\">*</span> <span class=\"n\">circle</span><span class=\"p\">)</span> <span class=\"o\">/</span> <span class=\"n\">n</span></pre>\n",
       "<pre class='cython code score-11 '>  <span class='pyx_macro_api'>__Pyx_XDECREF</span>(__pyx_r);\n",
       "  __pyx_t_8 = (4 * __pyx_v_circle);\n",
       "  if (unlikely(__pyx_v_n == 0)) {\n",
       "    <span class='py_c_api'>PyErr_SetString</span>(PyExc_ZeroDivisionError, \"float division\");\n",
       "    <span class='error_goto'>__PYX_ERR(0, 11, __pyx_L1_error)</span>\n",
       "  }\n",
       "  __pyx_t_9 = <span class='py_c_api'>PyFloat_FromDouble</span>((((double)__pyx_t_8) / ((double)__pyx_v_n)));<span class='error_goto'> if (unlikely(!__pyx_t_9)) __PYX_ERR(0, 11, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_9);\n",
       "  __pyx_r = __pyx_t_9;\n",
       "  __pyx_t_9 = 0;\n",
       "  goto __pyx_L0;\n",
       "</pre></div></body></html>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 95,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%%cython -a\n",
    "from libc.stdlib cimport rand\n",
    "cdef extern from 'limits.h':\n",
    "    int INT_MAX\n",
    "def mcs_pi_cy2(int n):\n",
    "    cdef int i, circle = 0\n",
    "    cdef float x, y\n",
    "    for i in range(n):\n",
    "        x, y = rand() / INT_MAX, rand() / INT_MAX\n",
    "        if (x ** 2 + y ** 2) ** 0.5 <= 1:\n",
    "            circle += 1\n",
    "    return (4 * circle) / n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 96,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 133 ms, sys: 1.44 ms, total: 134 ms\n",
      "Wall time: 135 ms\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "3.1419388"
      ]
     },
     "execution_count": 96,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time mcs_pi_cy2(n)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Binomial Trees"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Python"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 97,
   "metadata": {},
   "outputs": [],
   "source": [
    "import math"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 98,
   "metadata": {},
   "outputs": [],
   "source": [
    "S0 = 36.  \n",
    "T = 1.0  \n",
    "r = 0.06  \n",
    "sigma = 0.2  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 99,
   "metadata": {},
   "outputs": [],
   "source": [
    "def simulate_tree(M):\n",
    "    dt = T / M  \n",
    "    u = math.exp(sigma * math.sqrt(dt))  \n",
    "    d = 1 / u  \n",
    "    S = np.zeros((M + 1, M + 1))\n",
    "    S[0, 0] = S0\n",
    "    z = 1\n",
    "    for t in range(1, M + 1):\n",
    "        for i in range(z):\n",
    "            S[i, t] = S[i, t-1] * u\n",
    "            S[i+1, t] = S[i, t-1] * d\n",
    "        z += 1\n",
    "    return S"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 100,
   "metadata": {},
   "outputs": [],
   "source": [
    "np.set_printoptions(formatter={'float':\n",
    "                               lambda x: '%6.2f' % x})  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 101,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 36.00,  39.79,  43.97,  48.59,  53.71],\n",
       "       [  0.00,  32.57,  36.00,  39.79,  43.97],\n",
       "       [  0.00,   0.00,  29.47,  32.57,  36.00],\n",
       "       [  0.00,   0.00,   0.00,  26.67,  29.47],\n",
       "       [  0.00,   0.00,   0.00,   0.00,  24.13]])"
      ]
     },
     "execution_count": 101,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "simulate_tree(4)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 102,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 138 ms, sys: 4.5 ms, total: 142 ms\n",
      "Wall time: 143 ms\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([[ 36.00,  36.32,  36.65, ..., 3095.69, 3123.50, 3151.57],\n",
       "       [  0.00,  35.68,  36.00, ..., 3040.81, 3068.13, 3095.69],\n",
       "       [  0.00,   0.00,  35.36, ..., 2986.89, 3013.73, 3040.81],\n",
       "       ...,\n",
       "       [  0.00,   0.00,   0.00, ...,   0.42,   0.42,   0.43],\n",
       "       [  0.00,   0.00,   0.00, ...,   0.00,   0.41,   0.42],\n",
       "       [  0.00,   0.00,   0.00, ...,   0.00,   0.00,   0.41]])"
      ]
     },
     "execution_count": 102,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time simulate_tree(500)  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### NumPy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 103,
   "metadata": {},
   "outputs": [],
   "source": [
    "M = 4"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 104,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0, 1, 2, 3, 4],\n",
       "       [0, 1, 2, 3, 4],\n",
       "       [0, 1, 2, 3, 4],\n",
       "       [0, 1, 2, 3, 4],\n",
       "       [0, 1, 2, 3, 4]])"
      ]
     },
     "execution_count": 104,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "up = np.arange(M + 1)\n",
    "up = np.resize(up, (M + 1, M + 1))  \n",
    "up"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 105,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0, 0, 0, 0, 0],\n",
       "       [2, 2, 2, 2, 2],\n",
       "       [4, 4, 4, 4, 4],\n",
       "       [6, 6, 6, 6, 6],\n",
       "       [8, 8, 8, 8, 8]])"
      ]
     },
     "execution_count": 105,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "down = up.T * 2  \n",
    "down"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 106,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0,  1,  2,  3,  4],\n",
       "       [-2, -1,  0,  1,  2],\n",
       "       [-4, -3, -2, -1,  0],\n",
       "       [-6, -5, -4, -3, -2],\n",
       "       [-8, -7, -6, -5, -4]])"
      ]
     },
     "execution_count": 106,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "up - down  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 107,
   "metadata": {},
   "outputs": [],
   "source": [
    "dt = T / M"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 108,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 36.00,  39.79,  43.97,  48.59,  53.71],\n",
       "       [ 29.47,  32.57,  36.00,  39.79,  43.97],\n",
       "       [ 24.13,  26.67,  29.47,  32.57,  36.00],\n",
       "       [ 19.76,  21.84,  24.13,  26.67,  29.47],\n",
       "       [ 16.18,  17.88,  19.76,  21.84,  24.13]])"
      ]
     },
     "execution_count": 108,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "S0 * np.exp(sigma * math.sqrt(dt) * (up - down))  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 109,
   "metadata": {},
   "outputs": [],
   "source": [
    "def simulate_tree_np(M):\n",
    "    dt = T / M\n",
    "    up = np.arange(M + 1)\n",
    "    up = np.resize(up, (M + 1, M + 1))\n",
    "    down = up.transpose() * 2\n",
    "    S = S0 * np.exp(sigma * math.sqrt(dt) * (up - down))\n",
    "    return S"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 110,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 36.00,  39.79,  43.97,  48.59,  53.71],\n",
       "       [ 29.47,  32.57,  36.00,  39.79,  43.97],\n",
       "       [ 24.13,  26.67,  29.47,  32.57,  36.00],\n",
       "       [ 19.76,  21.84,  24.13,  26.67,  29.47],\n",
       "       [ 16.18,  17.88,  19.76,  21.84,  24.13]])"
      ]
     },
     "execution_count": 110,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "simulate_tree_np(4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 111,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 4.92 ms, sys: 3.57 ms, total: 8.49 ms\n",
      "Wall time: 7.41 ms\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([[ 36.00,  36.32,  36.65, ..., 3095.69, 3123.50, 3151.57],\n",
       "       [ 35.36,  35.68,  36.00, ..., 3040.81, 3068.13, 3095.69],\n",
       "       [ 34.73,  35.05,  35.36, ..., 2986.89, 3013.73, 3040.81],\n",
       "       ...,\n",
       "       [  0.00,   0.00,   0.00, ...,   0.42,   0.42,   0.43],\n",
       "       [  0.00,   0.00,   0.00, ...,   0.41,   0.41,   0.42],\n",
       "       [  0.00,   0.00,   0.00, ...,   0.40,   0.41,   0.41]])"
      ]
     },
     "execution_count": 111,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time simulate_tree_np(500)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Numba"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 112,
   "metadata": {},
   "outputs": [],
   "source": [
    "simulate_tree_nb = numba.jit(simulate_tree)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 113,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 36.00,  39.79,  43.97,  48.59,  53.71],\n",
       "       [  0.00,  32.57,  36.00,  39.79,  43.97],\n",
       "       [  0.00,   0.00,  29.47,  32.57,  36.00],\n",
       "       [  0.00,   0.00,   0.00,  26.67,  29.47],\n",
       "       [  0.00,   0.00,   0.00,   0.00,  24.13]])"
      ]
     },
     "execution_count": 113,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "simulate_tree_nb(4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 114,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 365 µs, sys: 0 ns, total: 365 µs\n",
      "Wall time: 370 µs\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([[ 36.00,  36.32,  36.65, ..., 3095.69, 3123.50, 3151.57],\n",
       "       [  0.00,  35.68,  36.00, ..., 3040.81, 3068.13, 3095.69],\n",
       "       [  0.00,   0.00,  35.36, ..., 2986.89, 3013.73, 3040.81],\n",
       "       ...,\n",
       "       [  0.00,   0.00,   0.00, ...,   0.42,   0.42,   0.43],\n",
       "       [  0.00,   0.00,   0.00, ...,   0.00,   0.41,   0.42],\n",
       "       [  0.00,   0.00,   0.00, ...,   0.00,   0.00,   0.41]])"
      ]
     },
     "execution_count": 114,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time simulate_tree_nb(500)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 115,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "308 µs ± 5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n"
     ]
    }
   ],
   "source": [
    "%timeit simulate_tree_nb(500)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Cython"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 116,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<!DOCTYPE html>\n",
       "<!-- Generated by Cython 0.29.20 -->\n",
       "<html>\n",
       "<head>\n",
       "    <meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" />\n",
       "    <title>Cython: _cython_magic_fe077a92a15c7c27b609d5de97b232a1.pyx</title>\n",
       "    <style type=\"text/css\">\n",
       "    \n",
       "body.cython { font-family: courier; font-size: 12; }\n",
       "\n",
       ".cython.tag  {  }\n",
       ".cython.line { margin: 0em }\n",
       ".cython.code { font-size: 9; color: #444444; display: none; margin: 0px 0px 0px 8px; border-left: 8px none; }\n",
       "\n",
       ".cython.line .run { background-color: #B0FFB0; }\n",
       ".cython.line .mis { background-color: #FFB0B0; }\n",
       ".cython.code.run  { border-left: 8px solid #B0FFB0; }\n",
       ".cython.code.mis  { border-left: 8px solid #FFB0B0; }\n",
       "\n",
       ".cython.code .py_c_api  { color: red; }\n",
       ".cython.code .py_macro_api  { color: #FF7000; }\n",
       ".cython.code .pyx_c_api  { color: #FF3000; }\n",
       ".cython.code .pyx_macro_api  { color: #FF7000; }\n",
       ".cython.code .refnanny  { color: #FFA000; }\n",
       ".cython.code .trace  { color: #FFA000; }\n",
       ".cython.code .error_goto  { color: #FFA000; }\n",
       "\n",
       ".cython.code .coerce  { color: #008000; border: 1px dotted #008000 }\n",
       ".cython.code .py_attr { color: #FF0000; font-weight: bold; }\n",
       ".cython.code .c_attr  { color: #0000FF; }\n",
       ".cython.code .py_call { color: #FF0000; font-weight: bold; }\n",
       ".cython.code .c_call  { color: #0000FF; }\n",
       "\n",
       ".cython.score-0 {background-color: #FFFFff;}\n",
       ".cython.score-1 {background-color: #FFFFe7;}\n",
       ".cython.score-2 {background-color: #FFFFd4;}\n",
       ".cython.score-3 {background-color: #FFFFc4;}\n",
       ".cython.score-4 {background-color: #FFFFb6;}\n",
       ".cython.score-5 {background-color: #FFFFaa;}\n",
       ".cython.score-6 {background-color: #FFFF9f;}\n",
       ".cython.score-7 {background-color: #FFFF96;}\n",
       ".cython.score-8 {background-color: #FFFF8d;}\n",
       ".cython.score-9 {background-color: #FFFF86;}\n",
       ".cython.score-10 {background-color: #FFFF7f;}\n",
       ".cython.score-11 {background-color: #FFFF79;}\n",
       ".cython.score-12 {background-color: #FFFF73;}\n",
       ".cython.score-13 {background-color: #FFFF6e;}\n",
       ".cython.score-14 {background-color: #FFFF6a;}\n",
       ".cython.score-15 {background-color: #FFFF66;}\n",
       ".cython.score-16 {background-color: #FFFF62;}\n",
       ".cython.score-17 {background-color: #FFFF5e;}\n",
       ".cython.score-18 {background-color: #FFFF5b;}\n",
       ".cython.score-19 {background-color: #FFFF57;}\n",
       ".cython.score-20 {background-color: #FFFF55;}\n",
       ".cython.score-21 {background-color: #FFFF52;}\n",
       ".cython.score-22 {background-color: #FFFF4f;}\n",
       ".cython.score-23 {background-color: #FFFF4d;}\n",
       ".cython.score-24 {background-color: #FFFF4b;}\n",
       ".cython.score-25 {background-color: #FFFF48;}\n",
       ".cython.score-26 {background-color: #FFFF46;}\n",
       ".cython.score-27 {background-color: #FFFF44;}\n",
       ".cython.score-28 {background-color: #FFFF43;}\n",
       ".cython.score-29 {background-color: #FFFF41;}\n",
       ".cython.score-30 {background-color: #FFFF3f;}\n",
       ".cython.score-31 {background-color: #FFFF3e;}\n",
       ".cython.score-32 {background-color: #FFFF3c;}\n",
       ".cython.score-33 {background-color: #FFFF3b;}\n",
       ".cython.score-34 {background-color: #FFFF39;}\n",
       ".cython.score-35 {background-color: #FFFF38;}\n",
       ".cython.score-36 {background-color: #FFFF37;}\n",
       ".cython.score-37 {background-color: #FFFF36;}\n",
       ".cython.score-38 {background-color: #FFFF35;}\n",
       ".cython.score-39 {background-color: #FFFF34;}\n",
       ".cython.score-40 {background-color: #FFFF33;}\n",
       ".cython.score-41 {background-color: #FFFF32;}\n",
       ".cython.score-42 {background-color: #FFFF31;}\n",
       ".cython.score-43 {background-color: #FFFF30;}\n",
       ".cython.score-44 {background-color: #FFFF2f;}\n",
       ".cython.score-45 {background-color: #FFFF2e;}\n",
       ".cython.score-46 {background-color: #FFFF2d;}\n",
       ".cython.score-47 {background-color: #FFFF2c;}\n",
       ".cython.score-48 {background-color: #FFFF2b;}\n",
       ".cython.score-49 {background-color: #FFFF2b;}\n",
       ".cython.score-50 {background-color: #FFFF2a;}\n",
       ".cython.score-51 {background-color: #FFFF29;}\n",
       ".cython.score-52 {background-color: #FFFF29;}\n",
       ".cython.score-53 {background-color: #FFFF28;}\n",
       ".cython.score-54 {background-color: #FFFF27;}\n",
       ".cython.score-55 {background-color: #FFFF27;}\n",
       ".cython.score-56 {background-color: #FFFF26;}\n",
       ".cython.score-57 {background-color: #FFFF26;}\n",
       ".cython.score-58 {background-color: #FFFF25;}\n",
       ".cython.score-59 {background-color: #FFFF24;}\n",
       ".cython.score-60 {background-color: #FFFF24;}\n",
       ".cython.score-61 {background-color: #FFFF23;}\n",
       ".cython.score-62 {background-color: #FFFF23;}\n",
       ".cython.score-63 {background-color: #FFFF22;}\n",
       ".cython.score-64 {background-color: #FFFF22;}\n",
       ".cython.score-65 {background-color: #FFFF22;}\n",
       ".cython.score-66 {background-color: #FFFF21;}\n",
       ".cython.score-67 {background-color: #FFFF21;}\n",
       ".cython.score-68 {background-color: #FFFF20;}\n",
       ".cython.score-69 {background-color: #FFFF20;}\n",
       ".cython.score-70 {background-color: #FFFF1f;}\n",
       ".cython.score-71 {background-color: #FFFF1f;}\n",
       ".cython.score-72 {background-color: #FFFF1f;}\n",
       ".cython.score-73 {background-color: #FFFF1e;}\n",
       ".cython.score-74 {background-color: #FFFF1e;}\n",
       ".cython.score-75 {background-color: #FFFF1e;}\n",
       ".cython.score-76 {background-color: #FFFF1d;}\n",
       ".cython.score-77 {background-color: #FFFF1d;}\n",
       ".cython.score-78 {background-color: #FFFF1c;}\n",
       ".cython.score-79 {background-color: #FFFF1c;}\n",
       ".cython.score-80 {background-color: #FFFF1c;}\n",
       ".cython.score-81 {background-color: #FFFF1c;}\n",
       ".cython.score-82 {background-color: #FFFF1b;}\n",
       ".cython.score-83 {background-color: #FFFF1b;}\n",
       ".cython.score-84 {background-color: #FFFF1b;}\n",
       ".cython.score-85 {background-color: #FFFF1a;}\n",
       ".cython.score-86 {background-color: #FFFF1a;}\n",
       ".cython.score-87 {background-color: #FFFF1a;}\n",
       ".cython.score-88 {background-color: #FFFF1a;}\n",
       ".cython.score-89 {background-color: #FFFF19;}\n",
       ".cython.score-90 {background-color: #FFFF19;}\n",
       ".cython.score-91 {background-color: #FFFF19;}\n",
       ".cython.score-92 {background-color: #FFFF19;}\n",
       ".cython.score-93 {background-color: #FFFF18;}\n",
       ".cython.score-94 {background-color: #FFFF18;}\n",
       ".cython.score-95 {background-color: #FFFF18;}\n",
       ".cython.score-96 {background-color: #FFFF18;}\n",
       ".cython.score-97 {background-color: #FFFF17;}\n",
       ".cython.score-98 {background-color: #FFFF17;}\n",
       ".cython.score-99 {background-color: #FFFF17;}\n",
       ".cython.score-100 {background-color: #FFFF17;}\n",
       ".cython.score-101 {background-color: #FFFF16;}\n",
       ".cython.score-102 {background-color: #FFFF16;}\n",
       ".cython.score-103 {background-color: #FFFF16;}\n",
       ".cython.score-104 {background-color: #FFFF16;}\n",
       ".cython.score-105 {background-color: #FFFF16;}\n",
       ".cython.score-106 {background-color: #FFFF15;}\n",
       ".cython.score-107 {background-color: #FFFF15;}\n",
       ".cython.score-108 {background-color: #FFFF15;}\n",
       ".cython.score-109 {background-color: #FFFF15;}\n",
       ".cython.score-110 {background-color: #FFFF15;}\n",
       ".cython.score-111 {background-color: #FFFF15;}\n",
       ".cython.score-112 {background-color: #FFFF14;}\n",
       ".cython.score-113 {background-color: #FFFF14;}\n",
       ".cython.score-114 {background-color: #FFFF14;}\n",
       ".cython.score-115 {background-color: #FFFF14;}\n",
       ".cython.score-116 {background-color: #FFFF14;}\n",
       ".cython.score-117 {background-color: #FFFF14;}\n",
       ".cython.score-118 {background-color: #FFFF13;}\n",
       ".cython.score-119 {background-color: #FFFF13;}\n",
       ".cython.score-120 {background-color: #FFFF13;}\n",
       ".cython.score-121 {background-color: #FFFF13;}\n",
       ".cython.score-122 {background-color: #FFFF13;}\n",
       ".cython.score-123 {background-color: #FFFF13;}\n",
       ".cython.score-124 {background-color: #FFFF13;}\n",
       ".cython.score-125 {background-color: #FFFF12;}\n",
       ".cython.score-126 {background-color: #FFFF12;}\n",
       ".cython.score-127 {background-color: #FFFF12;}\n",
       ".cython.score-128 {background-color: #FFFF12;}\n",
       ".cython.score-129 {background-color: #FFFF12;}\n",
       ".cython.score-130 {background-color: #FFFF12;}\n",
       ".cython.score-131 {background-color: #FFFF12;}\n",
       ".cython.score-132 {background-color: #FFFF11;}\n",
       ".cython.score-133 {background-color: #FFFF11;}\n",
       ".cython.score-134 {background-color: #FFFF11;}\n",
       ".cython.score-135 {background-color: #FFFF11;}\n",
       ".cython.score-136 {background-color: #FFFF11;}\n",
       ".cython.score-137 {background-color: #FFFF11;}\n",
       ".cython.score-138 {background-color: #FFFF11;}\n",
       ".cython.score-139 {background-color: #FFFF11;}\n",
       ".cython.score-140 {background-color: #FFFF11;}\n",
       ".cython.score-141 {background-color: #FFFF10;}\n",
       ".cython.score-142 {background-color: #FFFF10;}\n",
       ".cython.score-143 {background-color: #FFFF10;}\n",
       ".cython.score-144 {background-color: #FFFF10;}\n",
       ".cython.score-145 {background-color: #FFFF10;}\n",
       ".cython.score-146 {background-color: #FFFF10;}\n",
       ".cython.score-147 {background-color: #FFFF10;}\n",
       ".cython.score-148 {background-color: #FFFF10;}\n",
       ".cython.score-149 {background-color: #FFFF10;}\n",
       ".cython.score-150 {background-color: #FFFF0f;}\n",
       ".cython.score-151 {background-color: #FFFF0f;}\n",
       ".cython.score-152 {background-color: #FFFF0f;}\n",
       ".cython.score-153 {background-color: #FFFF0f;}\n",
       ".cython.score-154 {background-color: #FFFF0f;}\n",
       ".cython.score-155 {background-color: #FFFF0f;}\n",
       ".cython.score-156 {background-color: #FFFF0f;}\n",
       ".cython.score-157 {background-color: #FFFF0f;}\n",
       ".cython.score-158 {background-color: #FFFF0f;}\n",
       ".cython.score-159 {background-color: #FFFF0f;}\n",
       ".cython.score-160 {background-color: #FFFF0f;}\n",
       ".cython.score-161 {background-color: #FFFF0e;}\n",
       ".cython.score-162 {background-color: #FFFF0e;}\n",
       ".cython.score-163 {background-color: #FFFF0e;}\n",
       ".cython.score-164 {background-color: #FFFF0e;}\n",
       ".cython.score-165 {background-color: #FFFF0e;}\n",
       ".cython.score-166 {background-color: #FFFF0e;}\n",
       ".cython.score-167 {background-color: #FFFF0e;}\n",
       ".cython.score-168 {background-color: #FFFF0e;}\n",
       ".cython.score-169 {background-color: #FFFF0e;}\n",
       ".cython.score-170 {background-color: #FFFF0e;}\n",
       ".cython.score-171 {background-color: #FFFF0e;}\n",
       ".cython.score-172 {background-color: #FFFF0e;}\n",
       ".cython.score-173 {background-color: #FFFF0d;}\n",
       ".cython.score-174 {background-color: #FFFF0d;}\n",
       ".cython.score-175 {background-color: #FFFF0d;}\n",
       ".cython.score-176 {background-color: #FFFF0d;}\n",
       ".cython.score-177 {background-color: #FFFF0d;}\n",
       ".cython.score-178 {background-color: #FFFF0d;}\n",
       ".cython.score-179 {background-color: #FFFF0d;}\n",
       ".cython.score-180 {background-color: #FFFF0d;}\n",
       ".cython.score-181 {background-color: #FFFF0d;}\n",
       ".cython.score-182 {background-color: #FFFF0d;}\n",
       ".cython.score-183 {background-color: #FFFF0d;}\n",
       ".cython.score-184 {background-color: #FFFF0d;}\n",
       ".cython.score-185 {background-color: #FFFF0d;}\n",
       ".cython.score-186 {background-color: #FFFF0d;}\n",
       ".cython.score-187 {background-color: #FFFF0c;}\n",
       ".cython.score-188 {background-color: #FFFF0c;}\n",
       ".cython.score-189 {background-color: #FFFF0c;}\n",
       ".cython.score-190 {background-color: #FFFF0c;}\n",
       ".cython.score-191 {background-color: #FFFF0c;}\n",
       ".cython.score-192 {background-color: #FFFF0c;}\n",
       ".cython.score-193 {background-color: #FFFF0c;}\n",
       ".cython.score-194 {background-color: #FFFF0c;}\n",
       ".cython.score-195 {background-color: #FFFF0c;}\n",
       ".cython.score-196 {background-color: #FFFF0c;}\n",
       ".cython.score-197 {background-color: #FFFF0c;}\n",
       ".cython.score-198 {background-color: #FFFF0c;}\n",
       ".cython.score-199 {background-color: #FFFF0c;}\n",
       ".cython.score-200 {background-color: #FFFF0c;}\n",
       ".cython.score-201 {background-color: #FFFF0c;}\n",
       ".cython.score-202 {background-color: #FFFF0c;}\n",
       ".cython.score-203 {background-color: #FFFF0b;}\n",
       ".cython.score-204 {background-color: #FFFF0b;}\n",
       ".cython.score-205 {background-color: #FFFF0b;}\n",
       ".cython.score-206 {background-color: #FFFF0b;}\n",
       ".cython.score-207 {background-color: #FFFF0b;}\n",
       ".cython.score-208 {background-color: #FFFF0b;}\n",
       ".cython.score-209 {background-color: #FFFF0b;}\n",
       ".cython.score-210 {background-color: #FFFF0b;}\n",
       ".cython.score-211 {background-color: #FFFF0b;}\n",
       ".cython.score-212 {background-color: #FFFF0b;}\n",
       ".cython.score-213 {background-color: #FFFF0b;}\n",
       ".cython.score-214 {background-color: #FFFF0b;}\n",
       ".cython.score-215 {background-color: #FFFF0b;}\n",
       ".cython.score-216 {background-color: #FFFF0b;}\n",
       ".cython.score-217 {background-color: #FFFF0b;}\n",
       ".cython.score-218 {background-color: #FFFF0b;}\n",
       ".cython.score-219 {background-color: #FFFF0b;}\n",
       ".cython.score-220 {background-color: #FFFF0b;}\n",
       ".cython.score-221 {background-color: #FFFF0b;}\n",
       ".cython.score-222 {background-color: #FFFF0a;}\n",
       ".cython.score-223 {background-color: #FFFF0a;}\n",
       ".cython.score-224 {background-color: #FFFF0a;}\n",
       ".cython.score-225 {background-color: #FFFF0a;}\n",
       ".cython.score-226 {background-color: #FFFF0a;}\n",
       ".cython.score-227 {background-color: #FFFF0a;}\n",
       ".cython.score-228 {background-color: #FFFF0a;}\n",
       ".cython.score-229 {background-color: #FFFF0a;}\n",
       ".cython.score-230 {background-color: #FFFF0a;}\n",
       ".cython.score-231 {background-color: #FFFF0a;}\n",
       ".cython.score-232 {background-color: #FFFF0a;}\n",
       ".cython.score-233 {background-color: #FFFF0a;}\n",
       ".cython.score-234 {background-color: #FFFF0a;}\n",
       ".cython.score-235 {background-color: #FFFF0a;}\n",
       ".cython.score-236 {background-color: #FFFF0a;}\n",
       ".cython.score-237 {background-color: #FFFF0a;}\n",
       ".cython.score-238 {background-color: #FFFF0a;}\n",
       ".cython.score-239 {background-color: #FFFF0a;}\n",
       ".cython.score-240 {background-color: #FFFF0a;}\n",
       ".cython.score-241 {background-color: #FFFF0a;}\n",
       ".cython.score-242 {background-color: #FFFF0a;}\n",
       ".cython.score-243 {background-color: #FFFF0a;}\n",
       ".cython.score-244 {background-color: #FFFF0a;}\n",
       ".cython.score-245 {background-color: #FFFF0a;}\n",
       ".cython.score-246 {background-color: #FFFF09;}\n",
       ".cython.score-247 {background-color: #FFFF09;}\n",
       ".cython.score-248 {background-color: #FFFF09;}\n",
       ".cython.score-249 {background-color: #FFFF09;}\n",
       ".cython.score-250 {background-color: #FFFF09;}\n",
       ".cython.score-251 {background-color: #FFFF09;}\n",
       ".cython.score-252 {background-color: #FFFF09;}\n",
       ".cython.score-253 {background-color: #FFFF09;}\n",
       ".cython.score-254 {background-color: #FFFF09;}\n",
       ".cython .hll { background-color: #ffffcc }\n",
       ".cython  { background: #f8f8f8; }\n",
       ".cython .c { color: #408080; font-style: italic } /* Comment */\n",
       ".cython .err { border: 1px solid #FF0000 } /* Error */\n",
       ".cython .k { color: #008000; font-weight: bold } /* Keyword */\n",
       ".cython .o { color: #666666 } /* Operator */\n",
       ".cython .ch { color: #408080; font-style: italic } /* Comment.Hashbang */\n",
       ".cython .cm { color: #408080; font-style: italic } /* Comment.Multiline */\n",
       ".cython .cp { color: #BC7A00 } /* Comment.Preproc */\n",
       ".cython .cpf { color: #408080; font-style: italic } /* Comment.PreprocFile */\n",
       ".cython .c1 { color: #408080; font-style: italic } /* Comment.Single */\n",
       ".cython .cs { color: #408080; font-style: italic } /* Comment.Special */\n",
       ".cython .gd { color: #A00000 } /* Generic.Deleted */\n",
       ".cython .ge { font-style: italic } /* Generic.Emph */\n",
       ".cython .gr { color: #FF0000 } /* Generic.Error */\n",
       ".cython .gh { color: #000080; font-weight: bold } /* Generic.Heading */\n",
       ".cython .gi { color: #00A000 } /* Generic.Inserted */\n",
       ".cython .go { color: #888888 } /* Generic.Output */\n",
       ".cython .gp { color: #000080; font-weight: bold } /* Generic.Prompt */\n",
       ".cython .gs { font-weight: bold } /* Generic.Strong */\n",
       ".cython .gu { color: #800080; font-weight: bold } /* Generic.Subheading */\n",
       ".cython .gt { color: #0044DD } /* Generic.Traceback */\n",
       ".cython .kc { color: #008000; font-weight: bold } /* Keyword.Constant */\n",
       ".cython .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */\n",
       ".cython .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */\n",
       ".cython .kp { color: #008000 } /* Keyword.Pseudo */\n",
       ".cython .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */\n",
       ".cython .kt { color: #B00040 } /* Keyword.Type */\n",
       ".cython .m { color: #666666 } /* Literal.Number */\n",
       ".cython .s { color: #BA2121 } /* Literal.String */\n",
       ".cython .na { color: #7D9029 } /* Name.Attribute */\n",
       ".cython .nb { color: #008000 } /* Name.Builtin */\n",
       ".cython .nc { color: #0000FF; font-weight: bold } /* Name.Class */\n",
       ".cython .no { color: #880000 } /* Name.Constant */\n",
       ".cython .nd { color: #AA22FF } /* Name.Decorator */\n",
       ".cython .ni { color: #999999; font-weight: bold } /* Name.Entity */\n",
       ".cython .ne { color: #D2413A; font-weight: bold } /* Name.Exception */\n",
       ".cython .nf { color: #0000FF } /* Name.Function */\n",
       ".cython .nl { color: #A0A000 } /* Name.Label */\n",
       ".cython .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */\n",
       ".cython .nt { color: #008000; font-weight: bold } /* Name.Tag */\n",
       ".cython .nv { color: #19177C } /* Name.Variable */\n",
       ".cython .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */\n",
       ".cython .w { color: #bbbbbb } /* Text.Whitespace */\n",
       ".cython .mb { color: #666666 } /* Literal.Number.Bin */\n",
       ".cython .mf { color: #666666 } /* Literal.Number.Float */\n",
       ".cython .mh { color: #666666 } /* Literal.Number.Hex */\n",
       ".cython .mi { color: #666666 } /* Literal.Number.Integer */\n",
       ".cython .mo { color: #666666 } /* Literal.Number.Oct */\n",
       ".cython .sa { color: #BA2121 } /* Literal.String.Affix */\n",
       ".cython .sb { color: #BA2121 } /* Literal.String.Backtick */\n",
       ".cython .sc { color: #BA2121 } /* Literal.String.Char */\n",
       ".cython .dl { color: #BA2121 } /* Literal.String.Delimiter */\n",
       ".cython .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */\n",
       ".cython .s2 { color: #BA2121 } /* Literal.String.Double */\n",
       ".cython .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */\n",
       ".cython .sh { color: #BA2121 } /* Literal.String.Heredoc */\n",
       ".cython .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */\n",
       ".cython .sx { color: #008000 } /* Literal.String.Other */\n",
       ".cython .sr { color: #BB6688 } /* Literal.String.Regex */\n",
       ".cython .s1 { color: #BA2121 } /* Literal.String.Single */\n",
       ".cython .ss { color: #19177C } /* Literal.String.Symbol */\n",
       ".cython .bp { color: #008000 } /* Name.Builtin.Pseudo */\n",
       ".cython .fm { color: #0000FF } /* Name.Function.Magic */\n",
       ".cython .vc { color: #19177C } /* Name.Variable.Class */\n",
       ".cython .vg { color: #19177C } /* Name.Variable.Global */\n",
       ".cython .vi { color: #19177C } /* Name.Variable.Instance */\n",
       ".cython .vm { color: #19177C } /* Name.Variable.Magic */\n",
       ".cython .il { color: #666666 } /* Literal.Number.Integer.Long */\n",
       "    </style>\n",
       "</head>\n",
       "<body class=\"cython\">\n",
       "<p><span style=\"border-bottom: solid 1px grey;\">Generated by Cython 0.29.20</span></p>\n",
       "<p>\n",
       "    <span style=\"background-color: #FFFF00\">Yellow lines</span> hint at Python interaction.<br />\n",
       "    Click on a line that starts with a \"<code>+</code>\" to see the C code that Cython generated for it.\n",
       "</p>\n",
       "<div class=\"cython\"><pre class=\"cython line score-16\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">01</span>: <span class=\"k\">import</span> <span class=\"nn\">numpy</span> <span class=\"k\">as</span> <span class=\"nn\">np</span></pre>\n",
       "<pre class='cython code score-16 '>  __pyx_t_1 = <span class='pyx_c_api'>__Pyx_Import</span>(__pyx_n_s_numpy, 0, 0);<span class='error_goto'> if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_1);\n",
       "  if (<span class='py_c_api'>PyDict_SetItem</span>(__pyx_d, __pyx_n_s_np, __pyx_t_1) &lt; 0) <span class='error_goto'>__PYX_ERR(0, 1, __pyx_L1_error)</span>\n",
       "  <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_1); __pyx_t_1 = 0;\n",
       "/* … */\n",
       "  __pyx_t_1 = <span class='pyx_c_api'>__Pyx_PyDict_NewPresized</span>(0);<span class='error_goto'> if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 1, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_1);\n",
       "  if (<span class='py_c_api'>PyDict_SetItem</span>(__pyx_d, __pyx_n_s_test, __pyx_t_1) &lt; 0) <span class='error_goto'>__PYX_ERR(0, 1, __pyx_L1_error)</span>\n",
       "  <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_1); __pyx_t_1 = 0;\n",
       "</pre><pre class=\"cython line score-0\">&#xA0;<span class=\"\">02</span>: <span class=\"k\">cimport</span> <span class=\"nn\">cython</span></pre>\n",
       "<pre class=\"cython line score-0\">&#xA0;<span class=\"\">03</span>: <span class=\"k\">from</span> <span class=\"nn\">libc.math</span> <span class=\"k\">cimport</span> <span class=\"n\">exp</span><span class=\"p\">,</span> <span class=\"n\">sqrt</span></pre>\n",
       "<pre class=\"cython line score-0\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">04</span>: <span class=\"k\">cdef</span> <span class=\"kt\">float</span> <span class=\"nf\">S0</span> <span class=\"o\">=</span> <span class=\"mf\">36.</span></pre>\n",
       "<pre class='cython code score-0 '>  __pyx_v_46_cython_magic_fe077a92a15c7c27b609d5de97b232a1_S0 = 36.;\n",
       "</pre><pre class=\"cython line score-0\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">05</span>: <span class=\"k\">cdef</span> <span class=\"kt\">float</span> <span class=\"nf\">T</span> <span class=\"o\">=</span> <span class=\"mf\">1.0</span></pre>\n",
       "<pre class='cython code score-0 '>  __pyx_v_46_cython_magic_fe077a92a15c7c27b609d5de97b232a1_T = 1.0;\n",
       "</pre><pre class=\"cython line score-0\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">06</span>: <span class=\"k\">cdef</span> <span class=\"kt\">float</span> <span class=\"nf\">r</span> <span class=\"o\">=</span> <span class=\"mf\">0.06</span></pre>\n",
       "<pre class='cython code score-0 '>  __pyx_v_46_cython_magic_fe077a92a15c7c27b609d5de97b232a1_r = 0.06;\n",
       "</pre><pre class=\"cython line score-0\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">07</span>: <span class=\"k\">cdef</span> <span class=\"kt\">float</span> <span class=\"nf\">sigma</span> <span class=\"o\">=</span> <span class=\"mf\">0.2</span></pre>\n",
       "<pre class='cython code score-0 '>  __pyx_v_46_cython_magic_fe077a92a15c7c27b609d5de97b232a1_sigma = 0.2;\n",
       "</pre><pre class=\"cython line score-29\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">08</span>: <span class=\"k\">def</span> <span class=\"nf\">simulate_tree_cy</span><span class=\"p\">(</span><span class=\"nb\">int</span> <span class=\"n\">M</span><span class=\"p\">):</span></pre>\n",
       "<pre class='cython code score-29 '>/* Python wrapper */\n",
       "static PyObject *__pyx_pw_46_cython_magic_fe077a92a15c7c27b609d5de97b232a1_1simulate_tree_cy(PyObject *__pyx_self, PyObject *__pyx_arg_M); /*proto*/\n",
       "static PyMethodDef __pyx_mdef_46_cython_magic_fe077a92a15c7c27b609d5de97b232a1_1simulate_tree_cy = {\"simulate_tree_cy\", (PyCFunction)__pyx_pw_46_cython_magic_fe077a92a15c7c27b609d5de97b232a1_1simulate_tree_cy, METH_O, 0};\n",
       "static PyObject *__pyx_pw_46_cython_magic_fe077a92a15c7c27b609d5de97b232a1_1simulate_tree_cy(PyObject *__pyx_self, PyObject *__pyx_arg_M) {\n",
       "  int __pyx_v_M;\n",
       "  PyObject *__pyx_r = 0;\n",
       "  <span class='refnanny'>__Pyx_RefNannyDeclarations</span>\n",
       "  <span class='refnanny'>__Pyx_RefNannySetupContext</span>(\"simulate_tree_cy (wrapper)\", 0);\n",
       "  assert(__pyx_arg_M); {\n",
       "    __pyx_v_M = <span class='pyx_c_api'>__Pyx_PyInt_As_int</span>(__pyx_arg_M); if (unlikely((__pyx_v_M == (int)-1) &amp;&amp; <span class='py_c_api'>PyErr_Occurred</span>())) <span class='error_goto'>__PYX_ERR(0, 8, __pyx_L3_error)</span>\n",
       "  }\n",
       "  goto __pyx_L4_argument_unpacking_done;\n",
       "  __pyx_L3_error:;\n",
       "  <span class='pyx_c_api'>__Pyx_AddTraceback</span>(\"_cython_magic_fe077a92a15c7c27b609d5de97b232a1.simulate_tree_cy\", __pyx_clineno, __pyx_lineno, __pyx_filename);\n",
       "  <span class='refnanny'>__Pyx_RefNannyFinishContext</span>();\n",
       "  return NULL;\n",
       "  __pyx_L4_argument_unpacking_done:;\n",
       "  __pyx_r = __pyx_pf_46_cython_magic_fe077a92a15c7c27b609d5de97b232a1_simulate_tree_cy(__pyx_self, ((int)__pyx_v_M));\n",
       "  int __pyx_lineno = 0;\n",
       "  const char *__pyx_filename = NULL;\n",
       "  int __pyx_clineno = 0;\n",
       "\n",
       "  /* function exit code */\n",
       "  <span class='refnanny'>__Pyx_RefNannyFinishContext</span>();\n",
       "  return __pyx_r;\n",
       "}\n",
       "\n",
       "static PyObject *__pyx_pf_46_cython_magic_fe077a92a15c7c27b609d5de97b232a1_simulate_tree_cy(CYTHON_UNUSED PyObject *__pyx_self, int __pyx_v_M) {\n",
       "  int __pyx_v_z;\n",
       "  int __pyx_v_t;\n",
       "  int __pyx_v_i;\n",
       "  float __pyx_v_dt;\n",
       "  float __pyx_v_u;\n",
       "  float __pyx_v_d;\n",
       "  __Pyx_memviewslice __pyx_v_S = { 0, 0, { 0 }, { 0 }, { 0 } };\n",
       "  PyObject *__pyx_r = NULL;\n",
       "  <span class='refnanny'>__Pyx_RefNannyDeclarations</span>\n",
       "  <span class='refnanny'>__Pyx_RefNannySetupContext</span>(\"simulate_tree_cy\", 0);\n",
       "/* … */\n",
       "  /* function exit code */\n",
       "  __pyx_L1_error:;\n",
       "  <span class='pyx_macro_api'>__Pyx_XDECREF</span>(__pyx_t_1);\n",
       "  <span class='pyx_macro_api'>__Pyx_XDECREF</span>(__pyx_t_2);\n",
       "  <span class='pyx_macro_api'>__Pyx_XDECREF</span>(__pyx_t_3);\n",
       "  <span class='pyx_macro_api'>__Pyx_XDECREF</span>(__pyx_t_4);\n",
       "  <span class='pyx_macro_api'>__Pyx_XDECREF</span>(__pyx_t_5);\n",
       "  __PYX_XDEC_MEMVIEW(&amp;__pyx_t_6, 1);\n",
       "  <span class='pyx_c_api'>__Pyx_AddTraceback</span>(\"_cython_magic_fe077a92a15c7c27b609d5de97b232a1.simulate_tree_cy\", __pyx_clineno, __pyx_lineno, __pyx_filename);\n",
       "  __pyx_r = NULL;\n",
       "  __pyx_L0:;\n",
       "  __PYX_XDEC_MEMVIEW(&amp;__pyx_v_S, 1);\n",
       "  <span class='refnanny'>__Pyx_XGIVEREF</span>(__pyx_r);\n",
       "  <span class='refnanny'>__Pyx_RefNannyFinishContext</span>();\n",
       "  return __pyx_r;\n",
       "}\n",
       "/* … */\n",
       "  __pyx_tuple__19 = <span class='py_c_api'>PyTuple_Pack</span>(9, __pyx_n_s_M, __pyx_n_s_M, __pyx_n_s_z, __pyx_n_s_t, __pyx_n_s_i, __pyx_n_s_dt, __pyx_n_s_u, __pyx_n_s_d, __pyx_n_s_S);<span class='error_goto'> if (unlikely(!__pyx_tuple__19)) __PYX_ERR(0, 8, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_tuple__19);\n",
       "  <span class='refnanny'>__Pyx_GIVEREF</span>(__pyx_tuple__19);\n",
       "/* … */\n",
       "  __pyx_t_1 = PyCFunction_NewEx(&amp;__pyx_mdef_46_cython_magic_fe077a92a15c7c27b609d5de97b232a1_1simulate_tree_cy, NULL, __pyx_n_s_cython_magic_fe077a92a15c7c27b6);<span class='error_goto'> if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 8, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_1);\n",
       "  if (<span class='py_c_api'>PyDict_SetItem</span>(__pyx_d, __pyx_n_s_simulate_tree_cy, __pyx_t_1) &lt; 0) <span class='error_goto'>__PYX_ERR(0, 8, __pyx_L1_error)</span>\n",
       "  <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_1); __pyx_t_1 = 0;\n",
       "  __pyx_codeobj__20 = (PyObject*)<span class='pyx_c_api'>__Pyx_PyCode_New</span>(1, 0, 9, 0, CO_OPTIMIZED|CO_NEWLOCALS, __pyx_empty_bytes, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_tuple__19, __pyx_empty_tuple, __pyx_empty_tuple, __pyx_kp_s_Users_yves_ipython_cython__cyth, __pyx_n_s_simulate_tree_cy, 8, __pyx_empty_bytes);<span class='error_goto'> if (unlikely(!__pyx_codeobj__20)) __PYX_ERR(0, 8, __pyx_L1_error)</span>\n",
       "</pre><pre class=\"cython line score-0\">&#xA0;<span class=\"\">09</span>:     <span class=\"k\">cdef</span> <span class=\"kt\">int</span> <span class=\"nf\">z</span><span class=\"p\">,</span> <span class=\"nf\">t</span><span class=\"p\">,</span> <span class=\"nf\">i</span></pre>\n",
       "<pre class=\"cython line score-0\">&#xA0;<span class=\"\">10</span>:     <span class=\"k\">cdef</span> <span class=\"kt\">float</span> <span class=\"nf\">dt</span><span class=\"p\">,</span> <span class=\"nf\">u</span><span class=\"p\">,</span> <span class=\"nf\">d</span></pre>\n",
       "<pre class=\"cython line score-30\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">11</span>:     <span class=\"k\">cdef</span> <span class=\"kt\">float</span>[<span class=\"p\">:,</span> <span class=\"p\">:]</span> <span class=\"n\">S</span> <span class=\"o\">=</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">zeros</span><span class=\"p\">((</span><span class=\"n\">M</span> <span class=\"o\">+</span> <span class=\"mf\">1</span><span class=\"p\">,</span> <span class=\"n\">M</span> <span class=\"o\">+</span> <span class=\"mf\">1</span><span class=\"p\">),</span></pre>\n",
       "<pre class='cython code score-30 '>  <span class='pyx_c_api'>__Pyx_GetModuleGlobalName</span>(__pyx_t_1, __pyx_n_s_np);<span class='error_goto'> if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 11, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_1);\n",
       "  __pyx_t_2 = <span class='pyx_c_api'>__Pyx_PyObject_GetAttrStr</span>(__pyx_t_1, __pyx_n_s_zeros);<span class='error_goto'> if (unlikely(!__pyx_t_2)) __PYX_ERR(0, 11, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_2);\n",
       "  <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_1); __pyx_t_1 = 0;\n",
       "  __pyx_t_1 = <span class='pyx_c_api'>__Pyx_PyInt_From_long</span>((__pyx_v_M + 1));<span class='error_goto'> if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 11, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_1);\n",
       "  __pyx_t_3 = <span class='pyx_c_api'>__Pyx_PyInt_From_long</span>((__pyx_v_M + 1));<span class='error_goto'> if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 11, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_3);\n",
       "  __pyx_t_4 = <span class='py_c_api'>PyTuple_New</span>(2);<span class='error_goto'> if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 11, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_4);\n",
       "  <span class='refnanny'>__Pyx_GIVEREF</span>(__pyx_t_1);\n",
       "  <span class='py_macro_api'>PyTuple_SET_ITEM</span>(__pyx_t_4, 0, __pyx_t_1);\n",
       "  <span class='refnanny'>__Pyx_GIVEREF</span>(__pyx_t_3);\n",
       "  <span class='py_macro_api'>PyTuple_SET_ITEM</span>(__pyx_t_4, 1, __pyx_t_3);\n",
       "  __pyx_t_1 = 0;\n",
       "  __pyx_t_3 = 0;\n",
       "  __pyx_t_3 = <span class='py_c_api'>PyTuple_New</span>(1);<span class='error_goto'> if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 11, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_3);\n",
       "  <span class='refnanny'>__Pyx_GIVEREF</span>(__pyx_t_4);\n",
       "  <span class='py_macro_api'>PyTuple_SET_ITEM</span>(__pyx_t_3, 0, __pyx_t_4);\n",
       "  __pyx_t_4 = 0;\n",
       "/* … */\n",
       "  __pyx_t_5 = <span class='pyx_c_api'>__Pyx_PyObject_Call</span>(__pyx_t_2, __pyx_t_3, __pyx_t_4);<span class='error_goto'> if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 11, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_5);\n",
       "  <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_2); __pyx_t_2 = 0;\n",
       "  <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_3); __pyx_t_3 = 0;\n",
       "  <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_4); __pyx_t_4 = 0;\n",
       "  __pyx_t_6 = <span class='pyx_c_api'>__Pyx_PyObject_to_MemoryviewSlice_dsds_float</span>(__pyx_t_5, PyBUF_WRITABLE);<span class='error_goto'> if (unlikely(!__pyx_t_6.memview)) __PYX_ERR(0, 11, __pyx_L1_error)</span>\n",
       "  <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_5); __pyx_t_5 = 0;\n",
       "  __pyx_v_S = __pyx_t_6;\n",
       "  __pyx_t_6.memview = NULL;\n",
       "  __pyx_t_6.data = NULL;\n",
       "</pre><pre class=\"cython line score-13\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">12</span>:                                   <span class=\"n\">dtype</span><span class=\"o\">=</span><span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">float32</span><span class=\"p\">)</span></pre>\n",
       "<pre class='cython code score-13 '>  __pyx_t_4 = <span class='pyx_c_api'>__Pyx_PyDict_NewPresized</span>(1);<span class='error_goto'> if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 12, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_4);\n",
       "  <span class='pyx_c_api'>__Pyx_GetModuleGlobalName</span>(__pyx_t_1, __pyx_n_s_np);<span class='error_goto'> if (unlikely(!__pyx_t_1)) __PYX_ERR(0, 12, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_1);\n",
       "  __pyx_t_5 = <span class='pyx_c_api'>__Pyx_PyObject_GetAttrStr</span>(__pyx_t_1, __pyx_n_s_float32);<span class='error_goto'> if (unlikely(!__pyx_t_5)) __PYX_ERR(0, 12, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_5);\n",
       "  <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_1); __pyx_t_1 = 0;\n",
       "  if (<span class='py_c_api'>PyDict_SetItem</span>(__pyx_t_4, __pyx_n_s_dtype, __pyx_t_5) &lt; 0) <span class='error_goto'>__PYX_ERR(0, 12, __pyx_L1_error)</span>\n",
       "  <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_5); __pyx_t_5 = 0;\n",
       "</pre><pre class=\"cython line score-5\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">13</span>:     <span class=\"n\">dt</span> <span class=\"o\">=</span> <span class=\"n\">T</span> <span class=\"o\">/</span> <span class=\"n\">M</span></pre>\n",
       "<pre class='cython code score-5 '>  if (unlikely(__pyx_v_M == 0)) {\n",
       "    <span class='py_c_api'>PyErr_SetString</span>(PyExc_ZeroDivisionError, \"float division\");\n",
       "    <span class='error_goto'>__PYX_ERR(0, 13, __pyx_L1_error)</span>\n",
       "  }\n",
       "  __pyx_v_dt = (__pyx_v_46_cython_magic_fe077a92a15c7c27b609d5de97b232a1_T / ((float)__pyx_v_M));\n",
       "</pre><pre class=\"cython line score-0\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">14</span>:     <span class=\"n\">u</span> <span class=\"o\">=</span> <span class=\"n\">exp</span><span class=\"p\">(</span><span class=\"n\">sigma</span> <span class=\"o\">*</span> <span class=\"n\">sqrt</span><span class=\"p\">(</span><span class=\"n\">dt</span><span class=\"p\">))</span></pre>\n",
       "<pre class='cython code score-0 '>  __pyx_v_u = exp((__pyx_v_46_cython_magic_fe077a92a15c7c27b609d5de97b232a1_sigma * sqrt(__pyx_v_dt)));\n",
       "</pre><pre class=\"cython line score-5\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">15</span>:     <span class=\"n\">d</span> <span class=\"o\">=</span> <span class=\"mf\">1</span> <span class=\"o\">/</span> <span class=\"n\">u</span></pre>\n",
       "<pre class='cython code score-5 '>  if (unlikely(__pyx_v_u == 0)) {\n",
       "    <span class='py_c_api'>PyErr_SetString</span>(PyExc_ZeroDivisionError, \"float division\");\n",
       "    <span class='error_goto'>__PYX_ERR(0, 15, __pyx_L1_error)</span>\n",
       "  }\n",
       "  __pyx_v_d = (1.0 / __pyx_v_u);\n",
       "</pre><pre class=\"cython line score-2\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">16</span>:     <span class=\"n\">S</span><span class=\"p\">[</span><span class=\"mf\">0</span><span class=\"p\">,</span> <span class=\"mf\">0</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">S0</span></pre>\n",
       "<pre class='cython code score-2 '>  __pyx_t_7 = 0;\n",
       "  __pyx_t_8 = 0;\n",
       "  __pyx_t_9 = -1;\n",
       "  if (__pyx_t_7 &lt; 0) {\n",
       "    __pyx_t_7 += __pyx_v_S.shape[0];\n",
       "    if (unlikely(__pyx_t_7 &lt; 0)) __pyx_t_9 = 0;\n",
       "  } else if (unlikely(__pyx_t_7 &gt;= __pyx_v_S.shape[0])) __pyx_t_9 = 0;\n",
       "  if (__pyx_t_8 &lt; 0) {\n",
       "    __pyx_t_8 += __pyx_v_S.shape[1];\n",
       "    if (unlikely(__pyx_t_8 &lt; 0)) __pyx_t_9 = 1;\n",
       "  } else if (unlikely(__pyx_t_8 &gt;= __pyx_v_S.shape[1])) __pyx_t_9 = 1;\n",
       "  if (unlikely(__pyx_t_9 != -1)) {\n",
       "    <span class='pyx_c_api'>__Pyx_RaiseBufferIndexError</span>(__pyx_t_9);\n",
       "    <span class='error_goto'>__PYX_ERR(0, 16, __pyx_L1_error)</span>\n",
       "  }\n",
       "  *((float *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_S.data + __pyx_t_7 * __pyx_v_S.strides[0]) ) + __pyx_t_8 * __pyx_v_S.strides[1]) )) = __pyx_v_46_cython_magic_fe077a92a15c7c27b609d5de97b232a1_S0;\n",
       "</pre><pre class=\"cython line score-0\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">17</span>:     <span class=\"n\">z</span> <span class=\"o\">=</span> <span class=\"mf\">1</span></pre>\n",
       "<pre class='cython code score-0 '>  __pyx_v_z = 1;\n",
       "</pre><pre class=\"cython line score-0\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">18</span>:     <span class=\"k\">for</span> <span class=\"n\">t</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"mf\">1</span><span class=\"p\">,</span> <span class=\"n\">M</span> <span class=\"o\">+</span> <span class=\"mf\">1</span><span class=\"p\">):</span></pre>\n",
       "<pre class='cython code score-0 '>  __pyx_t_10 = (__pyx_v_M + 1);\n",
       "  __pyx_t_11 = __pyx_t_10;\n",
       "  for (__pyx_t_9 = 1; __pyx_t_9 &lt; __pyx_t_11; __pyx_t_9+=1) {\n",
       "    __pyx_v_t = __pyx_t_9;\n",
       "</pre><pre class=\"cython line score-0\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">19</span>:         <span class=\"k\">for</span> <span class=\"n\">i</span> <span class=\"ow\">in</span> <span class=\"nb\">range</span><span class=\"p\">(</span><span class=\"n\">z</span><span class=\"p\">):</span></pre>\n",
       "<pre class='cython code score-0 '>    __pyx_t_12 = __pyx_v_z;\n",
       "    __pyx_t_13 = __pyx_t_12;\n",
       "    for (__pyx_t_14 = 0; __pyx_t_14 &lt; __pyx_t_13; __pyx_t_14+=1) {\n",
       "      __pyx_v_i = __pyx_t_14;\n",
       "</pre><pre class=\"cython line score-4\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">20</span>:             <span class=\"n\">S</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"n\">t</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">S</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"n\">t</span><span class=\"o\">-</span><span class=\"mf\">1</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">u</span></pre>\n",
       "<pre class='cython code score-4 '>      __pyx_t_15 = __pyx_v_i;\n",
       "      __pyx_t_16 = (__pyx_v_t - 1);\n",
       "      __pyx_t_17 = -1;\n",
       "      if (__pyx_t_15 &lt; 0) {\n",
       "        __pyx_t_15 += __pyx_v_S.shape[0];\n",
       "        if (unlikely(__pyx_t_15 &lt; 0)) __pyx_t_17 = 0;\n",
       "      } else if (unlikely(__pyx_t_15 &gt;= __pyx_v_S.shape[0])) __pyx_t_17 = 0;\n",
       "      if (__pyx_t_16 &lt; 0) {\n",
       "        __pyx_t_16 += __pyx_v_S.shape[1];\n",
       "        if (unlikely(__pyx_t_16 &lt; 0)) __pyx_t_17 = 1;\n",
       "      } else if (unlikely(__pyx_t_16 &gt;= __pyx_v_S.shape[1])) __pyx_t_17 = 1;\n",
       "      if (unlikely(__pyx_t_17 != -1)) {\n",
       "        <span class='pyx_c_api'>__Pyx_RaiseBufferIndexError</span>(__pyx_t_17);\n",
       "        <span class='error_goto'>__PYX_ERR(0, 20, __pyx_L1_error)</span>\n",
       "      }\n",
       "      __pyx_t_18 = __pyx_v_i;\n",
       "      __pyx_t_19 = __pyx_v_t;\n",
       "      __pyx_t_17 = -1;\n",
       "      if (__pyx_t_18 &lt; 0) {\n",
       "        __pyx_t_18 += __pyx_v_S.shape[0];\n",
       "        if (unlikely(__pyx_t_18 &lt; 0)) __pyx_t_17 = 0;\n",
       "      } else if (unlikely(__pyx_t_18 &gt;= __pyx_v_S.shape[0])) __pyx_t_17 = 0;\n",
       "      if (__pyx_t_19 &lt; 0) {\n",
       "        __pyx_t_19 += __pyx_v_S.shape[1];\n",
       "        if (unlikely(__pyx_t_19 &lt; 0)) __pyx_t_17 = 1;\n",
       "      } else if (unlikely(__pyx_t_19 &gt;= __pyx_v_S.shape[1])) __pyx_t_17 = 1;\n",
       "      if (unlikely(__pyx_t_17 != -1)) {\n",
       "        <span class='pyx_c_api'>__Pyx_RaiseBufferIndexError</span>(__pyx_t_17);\n",
       "        <span class='error_goto'>__PYX_ERR(0, 20, __pyx_L1_error)</span>\n",
       "      }\n",
       "      *((float *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_S.data + __pyx_t_18 * __pyx_v_S.strides[0]) ) + __pyx_t_19 * __pyx_v_S.strides[1]) )) = ((*((float *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_S.data + __pyx_t_15 * __pyx_v_S.strides[0]) ) + __pyx_t_16 * __pyx_v_S.strides[1]) ))) * __pyx_v_u);\n",
       "</pre><pre class=\"cython line score-4\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">21</span>:             <span class=\"n\">S</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"o\">+</span><span class=\"mf\">1</span><span class=\"p\">,</span> <span class=\"n\">t</span><span class=\"p\">]</span> <span class=\"o\">=</span> <span class=\"n\">S</span><span class=\"p\">[</span><span class=\"n\">i</span><span class=\"p\">,</span> <span class=\"n\">t</span><span class=\"o\">-</span><span class=\"mf\">1</span><span class=\"p\">]</span> <span class=\"o\">*</span> <span class=\"n\">d</span></pre>\n",
       "<pre class='cython code score-4 '>      __pyx_t_16 = __pyx_v_i;\n",
       "      __pyx_t_15 = (__pyx_v_t - 1);\n",
       "      __pyx_t_17 = -1;\n",
       "      if (__pyx_t_16 &lt; 0) {\n",
       "        __pyx_t_16 += __pyx_v_S.shape[0];\n",
       "        if (unlikely(__pyx_t_16 &lt; 0)) __pyx_t_17 = 0;\n",
       "      } else if (unlikely(__pyx_t_16 &gt;= __pyx_v_S.shape[0])) __pyx_t_17 = 0;\n",
       "      if (__pyx_t_15 &lt; 0) {\n",
       "        __pyx_t_15 += __pyx_v_S.shape[1];\n",
       "        if (unlikely(__pyx_t_15 &lt; 0)) __pyx_t_17 = 1;\n",
       "      } else if (unlikely(__pyx_t_15 &gt;= __pyx_v_S.shape[1])) __pyx_t_17 = 1;\n",
       "      if (unlikely(__pyx_t_17 != -1)) {\n",
       "        <span class='pyx_c_api'>__Pyx_RaiseBufferIndexError</span>(__pyx_t_17);\n",
       "        <span class='error_goto'>__PYX_ERR(0, 21, __pyx_L1_error)</span>\n",
       "      }\n",
       "      __pyx_t_20 = (__pyx_v_i + 1);\n",
       "      __pyx_t_21 = __pyx_v_t;\n",
       "      __pyx_t_17 = -1;\n",
       "      if (__pyx_t_20 &lt; 0) {\n",
       "        __pyx_t_20 += __pyx_v_S.shape[0];\n",
       "        if (unlikely(__pyx_t_20 &lt; 0)) __pyx_t_17 = 0;\n",
       "      } else if (unlikely(__pyx_t_20 &gt;= __pyx_v_S.shape[0])) __pyx_t_17 = 0;\n",
       "      if (__pyx_t_21 &lt; 0) {\n",
       "        __pyx_t_21 += __pyx_v_S.shape[1];\n",
       "        if (unlikely(__pyx_t_21 &lt; 0)) __pyx_t_17 = 1;\n",
       "      } else if (unlikely(__pyx_t_21 &gt;= __pyx_v_S.shape[1])) __pyx_t_17 = 1;\n",
       "      if (unlikely(__pyx_t_17 != -1)) {\n",
       "        <span class='pyx_c_api'>__Pyx_RaiseBufferIndexError</span>(__pyx_t_17);\n",
       "        <span class='error_goto'>__PYX_ERR(0, 21, __pyx_L1_error)</span>\n",
       "      }\n",
       "      *((float *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_S.data + __pyx_t_20 * __pyx_v_S.strides[0]) ) + __pyx_t_21 * __pyx_v_S.strides[1]) )) = ((*((float *) ( /* dim=1 */ (( /* dim=0 */ (__pyx_v_S.data + __pyx_t_16 * __pyx_v_S.strides[0]) ) + __pyx_t_15 * __pyx_v_S.strides[1]) ))) * __pyx_v_d);\n",
       "    }\n",
       "</pre><pre class=\"cython line score-0\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">22</span>:         <span class=\"n\">z</span> <span class=\"o\">+=</span> <span class=\"mf\">1</span></pre>\n",
       "<pre class='cython code score-0 '>    __pyx_v_z = (__pyx_v_z + 1);\n",
       "  }\n",
       "</pre><pre class=\"cython line score-21\" onclick=\"(function(s){s.display=s.display==='block'?'none':'block'})(this.nextElementSibling.style)\">+<span class=\"\">23</span>:     <span class=\"k\">return</span> <span class=\"n\">np</span><span class=\"o\">.</span><span class=\"n\">array</span><span class=\"p\">(</span><span class=\"n\">S</span><span class=\"p\">)</span></pre>\n",
       "<pre class='cython code score-21 '>  <span class='pyx_macro_api'>__Pyx_XDECREF</span>(__pyx_r);\n",
       "  <span class='pyx_c_api'>__Pyx_GetModuleGlobalName</span>(__pyx_t_4, __pyx_n_s_np);<span class='error_goto'> if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 23, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_4);\n",
       "  __pyx_t_3 = <span class='pyx_c_api'>__Pyx_PyObject_GetAttrStr</span>(__pyx_t_4, __pyx_n_s_array);<span class='error_goto'> if (unlikely(!__pyx_t_3)) __PYX_ERR(0, 23, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_3);\n",
       "  <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_4); __pyx_t_4 = 0;\n",
       "  __pyx_t_4 = __pyx_memoryview_fromslice(__pyx_v_S, 2, (PyObject *(*)(char *)) __pyx_memview_get_float, (int (*)(char *, PyObject *)) __pyx_memview_set_float, 0);;<span class='error_goto'> if (unlikely(!__pyx_t_4)) __PYX_ERR(0, 23, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_4);\n",
       "  __pyx_t_2 = NULL;\n",
       "  if (CYTHON_UNPACK_METHODS &amp;&amp; unlikely(<span class='py_c_api'>PyMethod_Check</span>(__pyx_t_3))) {\n",
       "    __pyx_t_2 = <span class='py_macro_api'>PyMethod_GET_SELF</span>(__pyx_t_3);\n",
       "    if (likely(__pyx_t_2)) {\n",
       "      PyObject* function = <span class='py_macro_api'>PyMethod_GET_FUNCTION</span>(__pyx_t_3);\n",
       "      <span class='pyx_macro_api'>__Pyx_INCREF</span>(__pyx_t_2);\n",
       "      <span class='pyx_macro_api'>__Pyx_INCREF</span>(function);\n",
       "      <span class='pyx_macro_api'>__Pyx_DECREF_SET</span>(__pyx_t_3, function);\n",
       "    }\n",
       "  }\n",
       "  __pyx_t_5 = (__pyx_t_2) ? __Pyx_PyObject_Call2Args(__pyx_t_3, __pyx_t_2, __pyx_t_4) : <span class='pyx_c_api'>__Pyx_PyObject_CallOneArg</span>(__pyx_t_3, __pyx_t_4);\n",
       "  <span class='pyx_macro_api'>__Pyx_XDECREF</span>(__pyx_t_2); __pyx_t_2 = 0;\n",
       "  <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_4); __pyx_t_4 = 0;\n",
       "  if (unlikely(!__pyx_t_5)) <span class='error_goto'>__PYX_ERR(0, 23, __pyx_L1_error)</span>\n",
       "  <span class='refnanny'>__Pyx_GOTREF</span>(__pyx_t_5);\n",
       "  <span class='pyx_macro_api'>__Pyx_DECREF</span>(__pyx_t_3); __pyx_t_3 = 0;\n",
       "  __pyx_r = __pyx_t_5;\n",
       "  __pyx_t_5 = 0;\n",
       "  goto __pyx_L0;\n",
       "</pre></div></body></html>"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 116,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%%cython -a\n",
    "import numpy as np\n",
    "cimport cython\n",
    "from libc.math cimport exp, sqrt\n",
    "cdef float S0 = 36.\n",
    "cdef float T = 1.0\n",
    "cdef float r = 0.06\n",
    "cdef float sigma = 0.2\n",
    "def simulate_tree_cy(int M):\n",
    "    cdef int z, t, i\n",
    "    cdef float dt, u, d\n",
    "    cdef float[:, :] S = np.zeros((M + 1, M + 1),\n",
    "                                  dtype=np.float32)  \n",
    "    dt = T / M\n",
    "    u = exp(sigma * sqrt(dt))\n",
    "    d = 1 / u\n",
    "    S[0, 0] = S0\n",
    "    z = 1\n",
    "    for t in range(1, M + 1):\n",
    "        for i in range(z):\n",
    "            S[i, t] = S[i, t-1] * u\n",
    "            S[i+1, t] = S[i, t-1] * d\n",
    "        z += 1\n",
    "    return np.array(S)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 117,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 36.00,  39.79,  43.97,  48.59,  53.71],\n",
       "       [  0.00,  32.57,  36.00,  39.79,  43.97],\n",
       "       [  0.00,   0.00,  29.47,  32.57,  36.00],\n",
       "       [  0.00,   0.00,   0.00,  26.67,  29.47],\n",
       "       [  0.00,   0.00,   0.00,   0.00,  24.13]], dtype=float32)"
      ]
     },
     "execution_count": 117,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "simulate_tree_cy(4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 118,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 933 µs, sys: 580 µs, total: 1.51 ms\n",
      "Wall time: 722 µs\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "array([[ 36.00,  36.32,  36.65, ..., 3095.77, 3123.59, 3151.65],\n",
       "       [  0.00,  35.68,  36.00, ..., 3040.89, 3068.21, 3095.77],\n",
       "       [  0.00,   0.00,  35.36, ..., 2986.97, 3013.81, 3040.89],\n",
       "       ...,\n",
       "       [  0.00,   0.00,   0.00, ...,   0.42,   0.42,   0.43],\n",
       "       [  0.00,   0.00,   0.00, ...,   0.00,   0.41,   0.42],\n",
       "       [  0.00,   0.00,   0.00, ...,   0.00,   0.00,   0.41]],\n",
       "      dtype=float32)"
      ]
     },
     "execution_count": 118,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time simulate_tree_cy(500)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 119,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "267 µs ± 13.5 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n"
     ]
    }
   ],
   "source": [
    "%timeit S = simulate_tree_cy(500)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Monte Carlo Simulation"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Python"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 120,
   "metadata": {},
   "outputs": [],
   "source": [
    "M = 100  \n",
    "I = 50000  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 121,
   "metadata": {},
   "outputs": [],
   "source": [
    "def mcs_simulation_py(p):\n",
    "    M, I = p\n",
    "    dt = T / M\n",
    "    S = np.zeros((M + 1, I))\n",
    "    S[0] = S0\n",
    "    rn = np.random.standard_normal(S.shape)  \n",
    "    for t in range(1, M + 1):  \n",
    "        for i in range(I):  \n",
    "            S[t, i] = S[t-1, i] * math.exp((r - sigma ** 2 / 2) * dt +\n",
    "                                         sigma * math.sqrt(dt) * rn[t, i])  \n",
    "    return S      "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 122,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 6.21 s, sys: 19.6 ms, total: 6.23 s\n",
      "Wall time: 6.23 s\n"
     ]
    }
   ],
   "source": [
    "%time S = mcs_simulation_py((M, I))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 123,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "38.216018602103034"
      ]
     },
     "execution_count": 123,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "S[-1].mean()  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 124,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "38.22611567563295"
      ]
     },
     "execution_count": 124,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "S0 * math.exp(r * T)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 125,
   "metadata": {},
   "outputs": [],
   "source": [
    "K = 40.  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 126,
   "metadata": {},
   "outputs": [],
   "source": [
    "C0 = math.exp(-r * T) * np.maximum(K - S[-1], 0).mean()  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 127,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3.852776034283521"
      ]
     },
     "execution_count": 127,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "C0  #  <8>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 128,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.legend.Legend at 0x7faef5c3af50>"
      ]
     },
     "execution_count": 128,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 720x432 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(10, 6))\n",
    "plt.hist(S[-1], bins=35, label='frequency')\n",
    "plt.axvline(S[-1].mean(), color='r', label='mean value')\n",
    "plt.legend(loc=0)\n",
    "# plt.savefig('../../images/ch10/perf_02.png');"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### NumPy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 129,
   "metadata": {},
   "outputs": [],
   "source": [
    "def mcs_simulation_np(p):\n",
    "    M, I = p\n",
    "    dt = T / M\n",
    "    S = np.zeros((M + 1, I))\n",
    "    S[0] = S0\n",
    "    rn = np.random.standard_normal(S.shape)\n",
    "    for t in range(1, M + 1):  \n",
    "        S[t] = S[t-1] * np.exp((r - sigma ** 2 / 2) * dt +\n",
    "                               sigma * math.sqrt(dt) * rn[t]) \n",
    "    return S      "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 130,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 212 ms, sys: 17 ms, total: 229 ms\n",
      "Wall time: 233 ms\n"
     ]
    }
   ],
   "source": [
    "%time S = mcs_simulation_np((M, I))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 131,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "38.23062682996206"
      ]
     },
     "execution_count": 131,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "S[-1].mean()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 132,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "216 ms ± 8.38 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
     ]
    }
   ],
   "source": [
    "%timeit S = mcs_simulation_np((M, I))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Numba "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 133,
   "metadata": {},
   "outputs": [],
   "source": [
    "mcs_simulation_nb = numba.jit(mcs_simulation_py)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 134,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 489 ms, sys: 11 ms, total: 500 ms\n",
      "Wall time: 499 ms\n"
     ]
    }
   ],
   "source": [
    "%time S = mcs_simulation_nb((M, I))  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 135,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 184 ms, sys: 8.04 ms, total: 192 ms\n",
      "Wall time: 192 ms\n"
     ]
    }
   ],
   "source": [
    "%time S = mcs_simulation_nb((M, I))  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 136,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "38.200395241024054"
      ]
     },
     "execution_count": 136,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "S[-1].mean()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 137,
   "metadata": {},
   "outputs": [],
   "source": [
    "C0 = math.exp(-r * T) * np.maximum(K - S[-1], 0).mean()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 138,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3.8503057523340063"
      ]
     },
     "execution_count": 138,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "C0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 139,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "184 ms ± 3.79 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n"
     ]
    }
   ],
   "source": [
    "%timeit S = mcs_simulation_nb((M, I))  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Cython &mdash; Sequential"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 140,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%cython\n",
    "import numpy as np\n",
    "cimport numpy as np\n",
    "cimport cython\n",
    "from libc.math cimport exp, sqrt\n",
    "cdef float S0 = 36.\n",
    "cdef float T = 1.0\n",
    "cdef float r = 0.06\n",
    "cdef float sigma = 0.2\n",
    "@cython.boundscheck(False)\n",
    "@cython.wraparound(False)\n",
    "def mcs_simulation_cy(p):\n",
    "    cdef int M, I\n",
    "    M, I = p\n",
    "    cdef int t, i\n",
    "    cdef float dt = T / M\n",
    "    cdef double[:, :] S = np.zeros((M + 1, I))\n",
    "    cdef double[:, :] rn = np.random.standard_normal((M + 1, I))\n",
    "    S[0] = S0\n",
    "    for t in range(1, M + 1):\n",
    "        for i in range(I):\n",
    "            S[t, i] = S[t-1, i] * exp((r - sigma ** 2 / 2) * dt +\n",
    "                                         sigma * sqrt(dt) * rn[t, i])\n",
    "    return np.array(S) "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 141,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 216 ms, sys: 9.44 ms, total: 225 ms\n",
      "Wall time: 226 ms\n"
     ]
    }
   ],
   "source": [
    "%time S = mcs_simulation_cy((M, I))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 142,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "38.16427318224386"
      ]
     },
     "execution_count": 142,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "S[-1].mean()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 143,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "209 ms ± 1.82 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
     ]
    }
   ],
   "source": [
    "%timeit S = mcs_simulation_cy((M, I))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Multiprocessing"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 144,
   "metadata": {},
   "outputs": [],
   "source": [
    "import multiprocessing as mp"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 145,
   "metadata": {},
   "outputs": [],
   "source": [
    "pool = mp.Pool(processes=4)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 146,
   "metadata": {},
   "outputs": [],
   "source": [
    "p = 20  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 147,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "148 ms ± 7.19 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n"
     ]
    }
   ],
   "source": [
    "%timeit S = np.hstack(pool.map(mcs_simulation_np, p * [(M, int(I / p))]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 148,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "138 ms ± 6.18 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
     ]
    }
   ],
   "source": [
    "%timeit S = np.hstack(pool.map(mcs_simulation_nb, p * [(M, int(I / p))]))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 149,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "146 ms ± 1.99 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)\n"
     ]
    }
   ],
   "source": [
    "%timeit S = np.hstack(pool.map(mcs_simulation_cy, p * [(M, int(I / p))]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Recursive pandas Algorithm"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Data and Formula"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 150,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numba\n",
    "import numpy as np\n",
    "import pandas as pd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 151,
   "metadata": {},
   "outputs": [],
   "source": [
    "sym = 'SPY'"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 152,
   "metadata": {},
   "outputs": [],
   "source": [
    "data = pd.DataFrame(pd.read_csv('http://hilpisch.com/tr_eikon_eod_data.csv',\n",
    "                               index_col=0, parse_dates=True)[sym]).dropna()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 153,
   "metadata": {},
   "outputs": [],
   "source": [
    "alpha = 0.25"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 154,
   "metadata": {},
   "outputs": [],
   "source": [
    "data['EWMA'] = data[sym]  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 155,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 558 ms, sys: 17.4 ms, total: 575 ms\n",
      "Wall time: 560 ms\n"
     ]
    }
   ],
   "source": [
    "%%time\n",
    "for t in zip(data.index, data.index[1:]):\n",
    "    data.loc[t[1], 'EWMA'] = (alpha * data.loc[t[1], sym] +\n",
    "                              (1 - alpha) * data.loc[t[0], 'EWMA'])  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 156,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>SPY</th>\n",
       "      <th>EWMA</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Date</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2010-01-04</th>\n",
       "      <td>113.33</td>\n",
       "      <td>113.330000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-05</th>\n",
       "      <td>113.63</td>\n",
       "      <td>113.405000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-06</th>\n",
       "      <td>113.71</td>\n",
       "      <td>113.481250</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-07</th>\n",
       "      <td>114.19</td>\n",
       "      <td>113.658438</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-08</th>\n",
       "      <td>114.57</td>\n",
       "      <td>113.886328</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "               SPY        EWMA\n",
       "Date                          \n",
       "2010-01-04  113.33  113.330000\n",
       "2010-01-05  113.63  113.405000\n",
       "2010-01-06  113.71  113.481250\n",
       "2010-01-07  114.19  113.658438\n",
       "2010-01-08  114.57  113.886328"
      ]
     },
     "execution_count": 156,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 157,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 720x432 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "data[data.index > '2017-1-1'].plot(figsize=(10, 6));\n",
    "# plt.savefig('../../images/ch10/perf_03.png');"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Pure Python"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 158,
   "metadata": {},
   "outputs": [],
   "source": [
    "def ewma_py(x, alpha):\n",
    "    y = np.zeros_like(x)\n",
    "    y[0] = x[0]\n",
    "    for i in range(1, len(x)):\n",
    "        y[i] = alpha * x[i] + (1-alpha) * y[i-1]\n",
    "    return y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 159,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 44.7 ms, sys: 1.65 ms, total: 46.4 ms\n",
      "Wall time: 45.4 ms\n"
     ]
    }
   ],
   "source": [
    "%time data['EWMA_PY'] = ewma_py(data[sym], alpha)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 160,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 1.92 ms, sys: 166 µs, total: 2.08 ms\n",
      "Wall time: 1.94 ms\n"
     ]
    }
   ],
   "source": [
    "%time data['EWMA_PY'] = ewma_py(data[sym].values, alpha)  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Numba"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 161,
   "metadata": {},
   "outputs": [],
   "source": [
    "ewma_nb = numba.jit(ewma_py)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 162,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 119 ms, sys: 11.2 ms, total: 130 ms\n",
      "Wall time: 130 ms\n"
     ]
    }
   ],
   "source": [
    "%time data['EWMA_NB'] = ewma_nb(data[sym].values, alpha)  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 163,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "103 µs ± 6.76 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)\n"
     ]
    }
   ],
   "source": [
    "%timeit data['EWMA_NB'] = ewma_nb(data[sym].values, alpha)  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Cython"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 164,
   "metadata": {},
   "outputs": [],
   "source": [
    "%%cython\n",
    "import numpy as np\n",
    "cimport cython\n",
    "@cython.boundscheck(False)\n",
    "@cython.wraparound(False)\n",
    "def ewma_cy(double[:] x, float alpha):\n",
    "    cdef int i\n",
    "    cdef double[:] y = np.empty_like(x)\n",
    "    y[0] = x[0]\n",
    "    for i in range(1, len(x)):\n",
    "        y[i] = alpha * x[i] + (1 - alpha) * y[i - 1]\n",
    "    return y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 165,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "CPU times: user 1.26 ms, sys: 86 µs, total: 1.34 ms\n",
      "Wall time: 1.3 ms\n"
     ]
    }
   ],
   "source": [
    "%time data['EWMA_CY'] = ewma_cy(data[sym].values, alpha)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 166,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "529 µs ± 18.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)\n"
     ]
    }
   ],
   "source": [
    "%timeit data['EWMA_CY'] = ewma_cy(data[sym].values, alpha)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 167,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>SPY</th>\n",
       "      <th>EWMA</th>\n",
       "      <th>EWMA_PY</th>\n",
       "      <th>EWMA_NB</th>\n",
       "      <th>EWMA_CY</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Date</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2010-01-04</th>\n",
       "      <td>113.33</td>\n",
       "      <td>113.330000</td>\n",
       "      <td>113.330000</td>\n",
       "      <td>113.330000</td>\n",
       "      <td>113.330000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-05</th>\n",
       "      <td>113.63</td>\n",
       "      <td>113.405000</td>\n",
       "      <td>113.405000</td>\n",
       "      <td>113.405000</td>\n",
       "      <td>113.405000</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-06</th>\n",
       "      <td>113.71</td>\n",
       "      <td>113.481250</td>\n",
       "      <td>113.481250</td>\n",
       "      <td>113.481250</td>\n",
       "      <td>113.481250</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-07</th>\n",
       "      <td>114.19</td>\n",
       "      <td>113.658438</td>\n",
       "      <td>113.658438</td>\n",
       "      <td>113.658438</td>\n",
       "      <td>113.658438</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2010-01-08</th>\n",
       "      <td>114.57</td>\n",
       "      <td>113.886328</td>\n",
       "      <td>113.886328</td>\n",
       "      <td>113.886328</td>\n",
       "      <td>113.886328</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "               SPY        EWMA     EWMA_PY     EWMA_NB     EWMA_CY\n",
       "Date                                                              \n",
       "2010-01-04  113.33  113.330000  113.330000  113.330000  113.330000\n",
       "2010-01-05  113.63  113.405000  113.405000  113.405000  113.405000\n",
       "2010-01-06  113.71  113.481250  113.481250  113.481250  113.481250\n",
       "2010-01-07  114.19  113.658438  113.658438  113.658438  113.658438\n",
       "2010-01-08  114.57  113.886328  113.886328  113.886328  113.886328"
      ]
     },
     "execution_count": 167,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 168,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>SPY</th>\n",
       "      <th>EWMA</th>\n",
       "      <th>EWMA_PY</th>\n",
       "      <th>EWMA_NB</th>\n",
       "      <th>EWMA_CY</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>Date</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>2018-06-25</th>\n",
       "      <td>271.00</td>\n",
       "      <td>274.535176</td>\n",
       "      <td>274.535176</td>\n",
       "      <td>274.535176</td>\n",
       "      <td>274.535176</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2018-06-26</th>\n",
       "      <td>271.60</td>\n",
       "      <td>273.801382</td>\n",
       "      <td>273.801382</td>\n",
       "      <td>273.801382</td>\n",
       "      <td>273.801382</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2018-06-27</th>\n",
       "      <td>269.35</td>\n",
       "      <td>272.688537</td>\n",
       "      <td>272.688537</td>\n",
       "      <td>272.688537</td>\n",
       "      <td>272.688537</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2018-06-28</th>\n",
       "      <td>270.89</td>\n",
       "      <td>272.238903</td>\n",
       "      <td>272.238903</td>\n",
       "      <td>272.238903</td>\n",
       "      <td>272.238903</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2018-06-29</th>\n",
       "      <td>271.28</td>\n",
       "      <td>271.999177</td>\n",
       "      <td>271.999177</td>\n",
       "      <td>271.999177</td>\n",
       "      <td>271.999177</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "               SPY        EWMA     EWMA_PY     EWMA_NB     EWMA_CY\n",
       "Date                                                              \n",
       "2018-06-25  271.00  274.535176  274.535176  274.535176  274.535176\n",
       "2018-06-26  271.60  273.801382  273.801382  273.801382  273.801382\n",
       "2018-06-27  269.35  272.688537  272.688537  272.688537  272.688537\n",
       "2018-06-28  270.89  272.238903  272.238903  272.238903  272.238903\n",
       "2018-06-29  271.28  271.999177  271.999177  271.999177  271.999177"
      ]
     },
     "execution_count": 168,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "data.tail()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<img src=\"http://hilpisch.com/tpq_logo.png\" alt=\"The Python Quants\" width=\"35%\" align=\"right\" border=\"0\"><br>\n",
    "\n",
    "<a href=\"http://tpq.io\" target=\"_blank\">http://tpq.io</a> | <a href=\"http://twitter.com/dyjh\" target=\"_blank\">@dyjh</a> | <a href=\"mailto:training@tpq.io\">training@tpq.io</a>"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
